aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/topology.c148
-rw-r--r--drivers/block/umem.c2
-rw-r--r--drivers/char/cyclades.c6
-rw-r--r--drivers/char/esp.c4
-rw-r--r--drivers/char/ip2/i2cmd.c1
-rw-r--r--drivers/char/ip2main.c67
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c4
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c24
-rw-r--r--drivers/char/rio/cirrus.h142
-rw-r--r--drivers/char/rio/defaults.h7
-rw-r--r--drivers/char/rio/link.h34
-rw-r--r--drivers/char/rio/list.h140
-rw-r--r--drivers/char/rio/parmmap.h5
-rw-r--r--drivers/char/rio/phb.h133
-rw-r--r--drivers/char/rio/pkt.h27
-rw-r--r--drivers/char/rio/qbuf.h4
-rw-r--r--drivers/char/rio/riotypes.h66
-rw-r--r--drivers/char/rio/rup.h5
-rw-r--r--drivers/char/rio/sam.h4
-rw-r--r--drivers/char/rocket.c2
-rw-r--r--drivers/char/sx.c6
-rw-r--r--drivers/char/tty_io.c77
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c13
-rw-r--r--drivers/edac/Kconfig2
-rw-r--r--drivers/edac/e752x_edac.c8
-rw-r--r--drivers/edac/edac_mc.c1
-rw-r--r--drivers/ide/Kconfig25
-rw-r--r--drivers/ide/ide-disk.c8
-rw-r--r--drivers/ide/ide-io.c5
-rw-r--r--drivers/ide/ide-iops.c1
-rw-r--r--drivers/ide/ide-probe.c51
-rw-r--r--drivers/ide/ide.c1
-rw-r--r--drivers/ide/pci/aec62xx.c15
-rw-r--r--drivers/ide/pci/hpt366.c4
-rw-r--r--drivers/ide/pci/it821x.c2
-rw-r--r--drivers/ide/pci/pdc202xx_new.c6
-rw-r--r--drivers/ide/pci/pdc202xx_old.c15
-rw-r--r--drivers/ide/pci/piix.c4
-rw-r--r--drivers/isdn/hisax/hisax.h2
-rw-r--r--drivers/isdn/sc/ioctl.c4
-rw-r--r--drivers/md/md.c18
-rw-r--r--drivers/md/raid0.c2
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/md/raid5.c3
-rw-r--r--drivers/md/raid6main.c3
-rw-r--r--drivers/message/i2o/core.h3
-rw-r--r--drivers/message/i2o/pci.c47
-rw-r--r--drivers/mtd/maps/dc21285.c9
-rw-r--r--drivers/net/3c59x.c33
-rw-r--r--drivers/parport/Kconfig9
-rw-r--r--drivers/parport/Makefile1
-rw-r--r--drivers/parport/ieee1284.c10
-rw-r--r--drivers/parport/parport_ip32.c2253
-rw-r--r--drivers/parport/parport_serial.c4
-rw-r--r--drivers/parport/probe.c4
-rw-r--r--drivers/s390/block/Kconfig14
-rw-r--r--drivers/s390/block/Makefile2
-rw-r--r--drivers/s390/block/dasd.c76
-rw-r--r--drivers/s390/block/dasd_3990_erp.c3
-rw-r--r--drivers/s390/block/dasd_eckd.h1
-rw-r--r--drivers/s390/block/dasd_eer.c1090
-rw-r--r--drivers/s390/block/dasd_int.h37
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/serial/Kconfig28
-rw-r--r--drivers/serial/jsm/jsm.h1
-rw-r--r--drivers/serial/jsm/jsm_driver.c3
-rw-r--r--drivers/serial/jsm/jsm_tty.c209
-rw-r--r--drivers/serial/mcfserial.c3
-rw-r--r--drivers/telephony/ixj.c14
70 files changed, 3961 insertions, 999 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index f12898d53078..e99471d3232b 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -8,6 +8,7 @@ obj-y += power/
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
+obj-$(CONFIG_SMP) += topology.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
new file mode 100644
index 000000000000..915810f6237e
--- /dev/null
+++ b/drivers/base/topology.c
@@ -0,0 +1,148 @@
+/*
+ * driver/base/topology.c - Populate sysfs with cpu topology information
+ *
+ * Written by: Zhang Yanmin, Intel Corporation
+ *
+ * Copyright (C) 2006, Intel Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/topology.h>
+
+#define define_one_ro(_name) \
+static SYSDEV_ATTR(_name, 0444, show_##_name, NULL)
+
+#define define_id_show_func(name) \
+static ssize_t show_##name(struct sys_device *dev, char *buf) \
+{ \
+ unsigned int cpu = dev->id; \
+ return sprintf(buf, "%d\n", topology_##name(cpu)); \
+}
+
+#define define_siblings_show_func(name) \
+static ssize_t show_##name(struct sys_device *dev, char *buf) \
+{ \
+ ssize_t len = -1; \
+ unsigned int cpu = dev->id; \
+ len = cpumask_scnprintf(buf, NR_CPUS+1, topology_##name(cpu)); \
+ return (len + sprintf(buf + len, "\n")); \
+}
+
+#ifdef topology_physical_package_id
+define_id_show_func(physical_package_id);
+define_one_ro(physical_package_id);
+#define ref_physical_package_id_attr &attr_physical_package_id.attr,
+#else
+#define ref_physical_package_id_attr
+#endif
+
+#ifdef topology_core_id
+define_id_show_func(core_id);
+define_one_ro(core_id);
+#define ref_core_id_attr &attr_core_id.attr,
+#else
+#define ref_core_id_attr
+#endif
+
+#ifdef topology_thread_siblings
+define_siblings_show_func(thread_siblings);
+define_one_ro(thread_siblings);
+#define ref_thread_siblings_attr &attr_thread_siblings.attr,
+#else
+#define ref_thread_siblings_attr
+#endif
+
+#ifdef topology_core_siblings
+define_siblings_show_func(core_siblings);
+define_one_ro(core_siblings);
+#define ref_core_siblings_attr &attr_core_siblings.attr,
+#else
+#define ref_core_siblings_attr
+#endif
+
+static struct attribute *default_attrs[] = {
+ ref_physical_package_id_attr
+ ref_core_id_attr
+ ref_thread_siblings_attr
+ ref_core_siblings_attr
+ NULL
+};
+
+static struct attribute_group topology_attr_group = {
+ .attrs = default_attrs,
+ .name = "topology"
+};
+
+/* Add/Remove cpu_topology interface for CPU device */
+static int __cpuinit topology_add_dev(struct sys_device * sys_dev)
+{
+ sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
+ return 0;
+}
+
+static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
+{
+ sysfs_remove_group(&sys_dev->kobj, &topology_attr_group);
+ return 0;
+}
+
+static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct sys_device *sys_dev;
+
+ sys_dev = get_cpu_sysdev(cpu);
+ switch (action) {
+ case CPU_ONLINE:
+ topology_add_dev(sys_dev);
+ break;
+ case CPU_DEAD:
+ topology_remove_dev(sys_dev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block topology_cpu_notifier =
+{
+ .notifier_call = topology_cpu_callback,
+};
+
+static int __cpuinit topology_sysfs_init(void)
+{
+ int i;
+
+ for_each_online_cpu(i) {
+ topology_cpu_callback(&topology_cpu_notifier, CPU_ONLINE,
+ (void *)(long)i);
+ }
+
+ register_cpu_notifier(&topology_cpu_notifier);
+
+ return 0;
+}
+
+device_initcall(topology_sysfs_init);
+
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index a3614e6a68d0..4ada1268b40d 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -882,7 +882,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->card_number, dev->bus->number, dev->devfn);
if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) &&
- !pci_set_dma_mask(dev, 0xffffffffLL)) {
+ pci_set_dma_mask(dev, 0xffffffffLL)) {
printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
return -ENOMEM;
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 39c61a71176e..cc7acf877dc0 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1233,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
info->idle_stats.recv_idle = jiffies;
}
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
/* end of service */
cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f));
@@ -1606,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info,
}
#endif
info->idle_stats.recv_idle = jiffies;
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
/* Update rx_get */
cy_writel(&buf_ctrl->rx_get, new_rx_get);
@@ -1809,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
if(delta_count)
cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
if(special_count)
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
}
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 3f3ac039f4d9..57539d8f9f7c 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -359,7 +359,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
}
}
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
release_pio_buffer(pio_buf);
@@ -426,7 +426,7 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
}
tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
}
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
if (dma_bytes != num_bytes) {
diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c
index cb8f4198e9a3..e7af647800b6 100644
--- a/drivers/char/ip2/i2cmd.c
+++ b/drivers/char/ip2/i2cmd.c
@@ -139,7 +139,6 @@ static UCHAR ct79[] = { 2, BYP, 0x4F,0 }; // XMIT_NOW
//static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE
static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST
//static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD
-static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW
//static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO
//static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 56e93a5a1e24..48fcfba37bfa 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -2906,65 +2906,16 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
rc = -EINVAL;
break;
case 3: // Trace device
- if ( cmd == 1 ) {
- rc = put_user(iiSendPendingMail, pIndex++ );
- rc = put_user(i2InitChannels, pIndex++ );
- rc = put_user(i2QueueNeeds, pIndex++ );
- rc = put_user(i2QueueCommands, pIndex++ );
- rc = put_user(i2GetStatus, pIndex++ );
- rc = put_user(i2Input, pIndex++ );
- rc = put_user(i2InputFlush, pIndex++ );
- rc = put_user(i2Output, pIndex++ );
- rc = put_user(i2FlushOutput, pIndex++ );
- rc = put_user(i2DrainWakeup, pIndex++ );
- rc = put_user(i2DrainOutput, pIndex++ );
- rc = put_user(i2OutputFree, pIndex++ );
- rc = put_user(i2StripFifo, pIndex++ );
- rc = put_user(i2StuffFifoBypass, pIndex++ );
- rc = put_user(i2StuffFifoFlow, pIndex++ );
- rc = put_user(i2StuffFifoInline, pIndex++ );
- rc = put_user(i2ServiceBoard, pIndex++ );
- rc = put_user(serviceOutgoingFifo, pIndex++ );
- // rc = put_user(ip2_init, pIndex++ );
- rc = put_user(ip2_init_board, pIndex++ );
- rc = put_user(find_eisa_board, pIndex++ );
- rc = put_user(set_irq, pIndex++ );
- rc = put_user(ip2_interrupt, pIndex++ );
- rc = put_user(ip2_poll, pIndex++ );
- rc = put_user(service_all_boards, pIndex++ );
- rc = put_user(do_input, pIndex++ );
- rc = put_user(do_status, pIndex++ );
-#ifndef IP2DEBUG_OPEN
- rc = put_user(0, pIndex++ );
-#else
- rc = put_user(open_sanity_check, pIndex++ );
-#endif
- rc = put_user(ip2_open, pIndex++ );
- rc = put_user(ip2_close, pIndex++ );
- rc = put_user(ip2_hangup, pIndex++ );
- rc = put_user(ip2_write, pIndex++ );
- rc = put_user(ip2_putchar, pIndex++ );
- rc = put_user(ip2_flush_chars, pIndex++ );
- rc = put_user(ip2_write_room, pIndex++ );
- rc = put_user(ip2_chars_in_buf, pIndex++ );
- rc = put_user(ip2_flush_buffer, pIndex++ );
-
- //rc = put_user(ip2_wait_until_sent, pIndex++ );
- rc = put_user(0, pIndex++ );
-
- rc = put_user(ip2_throttle, pIndex++ );
- rc = put_user(ip2_unthrottle, pIndex++ );
- rc = put_user(ip2_ioctl, pIndex++ );
- rc = put_user(0, pIndex++ );
- rc = put_user(get_serial_info, pIndex++ );
- rc = put_user(set_serial_info, pIndex++ );
- rc = put_user(ip2_set_termios, pIndex++ );
- rc = put_user(ip2_set_line_discipline, pIndex++ );
- rc = put_user(set_params, pIndex++ );
- } else {
+ /*
+ * akpm: This used to write a whole bunch of function addresses
+ * to userspace, which generated lots of put_user() warnings.
+ * I killed it all. Just return "success" and don't do
+ * anything.
+ */
+ if (cmd == 1)
+ rc = 0;
+ else
rc = -EINVAL;
- }
-
break;
default:
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 0097f06fa67b..d745004281d0 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -481,7 +481,7 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len)
}
if ((addr->channel == IPMI_BMC_CHANNEL)
- || (addr->channel >= IPMI_NUM_CHANNELS)
+ || (addr->channel >= IPMI_MAX_CHANNELS)
|| (addr->channel < 0))
return -EINVAL;
@@ -1321,7 +1321,7 @@ static int i_ipmi_request(ipmi_user_t user,
unsigned char ipmb_seq;
long seqid;
- if (addr->channel >= IPMI_NUM_CHANNELS) {
+ if (addr->channel >= IPMI_MAX_CHANNELS) {
spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 6ed213bd702c..e59b638766ef 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1270,36 +1270,36 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
return 0;
}
-static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset)
{
return readb((io->addr)+(offset * io->regspacing));
}
-static void mem_outb(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outb(struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
writeb(b, (io->addr)+(offset * io->regspacing));
}
-static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset)
{
return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
&& 0xff;
}
-static void mem_outw(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outw(struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
}
-static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset)
{
return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
&& 0xff;
}
-static void mem_outl(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outl(struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
@@ -1349,16 +1349,16 @@ static int mem_setup(struct smi_info *info)
upon the register size. */
switch (info->io.regsize) {
case 1:
- info->io.inputb = mem_inb;
- info->io.outputb = mem_outb;
+ info->io.inputb = intf_mem_inb;
+ info->io.outputb = intf_mem_outb;
break;
case 2:
- info->io.inputb = mem_inw;
- info->io.outputb = mem_outw;
+ info->io.inputb = intf_mem_inw;
+ info->io.outputb = intf_mem_outw;
break;
case 4:
- info->io.inputb = mem_inl;
- info->io.outputb = mem_outl;
+ info->io.inputb = intf_mem_inl;
+ info->io.outputb = intf_mem_outl;
break;
#ifdef readq
case 8:
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
index 217ff09f2fa1..89bd94eb45be 100644
--- a/drivers/char/rio/cirrus.h
+++ b/drivers/char/rio/cirrus.h
@@ -40,148 +40,6 @@
#endif
#define _cirrus_h 1
-#ifdef RTA
-#define TO_UART RX
-#define TO_DRIVER TX
-#endif
-
-#ifdef HOST
-#define TO_UART TX
-#define TO_DRIVER RX
-#endif
-#ifdef RTA
-/* Miscellaneous defines for CIRRUS addresses and related logic for
- interrupts etc.
-*/
-#define MAP(a) ((short *)(cirrus_base + (a)))
-#define outp(a,b) (*MAP (a) =(b))
-#define inp(a) ((*MAP (a)) & 0xff)
-#define CIRRUS_FIRST (short*)0x7300
-#define CIRRUS_SECOND (short*)0x7200
-#define CIRRUS_THIRD (short*)0x7100
-#define CIRRUS_FOURTH (short*)0x7000
-#define PORTS_ON_CIRRUS 4
-#define CIRRUS_FIFO_SIZE 12
-#define SPACE 0x20
-#define TAB 0x09
-#define LINE_FEED 0x0a
-#define CARRIAGE_RETURN 0x0d
-#define BACKSPACE 0x08
-#define SPACES_IN_TABS 8
-#define SEND_ESCAPE 0x00
-#define START_BREAK 0x81
-#define TIMER_TICK 0x82
-#define STOP_BREAK 0x83
-#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH)))
-#define txack1 ((short *)0x7104)
-#define rxack1 ((short *)0x7102)
-#define mdack1 ((short *)0x7106)
-#define txack2 ((short *)0x7006)
-#define rxack2 ((short *)0x7004)
-#define mdack2 ((short *)0x7100)
-#define int_latch ((short *) 0x7800)
-#define int_status ((short *) 0x7c00)
-#define tx1_pending 0x20
-#define rx1_pending 0x10
-#define md1_pending 0x40
-#define tx2_pending 0x02
-#define rx2_pending 0x01
-#define md2_pending 0x40
-#define module1_bits 0x07
-#define module1_modern 0x08
-#define module2_bits 0x70
-#define module2_modern 0x80
-#define module_blank 0xf
-#define rs232_d25 0x0
-#define rs232_rj45 0x1
-#define rs422_d25 0x3
-#define parallel 0x5
-
-#define CLK0 0x00
-#define CLK1 0x01
-#define CLK2 0x02
-#define CLK3 0x03
-#define CLK4 0x04
-
-#define CIRRUS_REVC 0x42
-#define CIRRUS_REVE 0x44
-
-#define TURNON 1
-#define TURNOFF 0
-
-/* The list of CIRRUS registers.
- NB. These registers are relative values on 8 bit boundaries whereas
- on the RTA's the CIRRUS registers are on word boundaries. Use pointer
- arithmetic (short *) to obtain the real addresses required */
-#define ccr 0x05 /* Channel Command Register */
-#define ier 0x06 /* Interrupt Enable Register */
-#define cor1 0x08 /* Channel Option Register 1 */
-#define cor2 0x09 /* Channel Option Register 2 */
-#define cor3 0x0a /* Channel Option Register 3 */
-#define cor4 0x1e /* Channel Option Register 4 */
-#define cor5 0x1f /* Channel Option Register 5 */
-
-#define ccsr 0x0b /* Channel Control Status Register */
-#define rdcr 0x0e /* Receive Data Count Register */
-#define tdcr 0x12 /* Transmit Data Count Register */
-#define mcor1 0x15 /* Modem Change Option Register 1 */
-#define mcor2 0x16 /* Modem Change Option Regsiter 2 */
-
-#define livr 0x18 /* Local Interrupt Vector Register */
-#define schr1 0x1a /* Special Character Register 1 */
-#define schr2 0x1b /* Special Character Register 2 */
-#define schr3 0x1c /* Special Character Register 3 */
-#define schr4 0x1d /* Special Character Register 4 */
-
-#define rtr 0x20 /* Receive Timer Register */
-#define rtpr 0x21 /* Receive Timeout Period Register */
-#define lnc 0x24 /* Lnext character */
-
-#define rivr 0x43 /* Receive Interrupt Vector Register */
-#define tivr 0x42 /* Transmit Interrupt Vector Register */
-#define mivr 0x41 /* Modem Interrupt Vector Register */
-#define gfrcr 0x40 /* Global Firmware Revision code Reg */
-#define ricr 0x44 /* Receive Interrupting Channel Reg */
-#define ticr 0x45 /* Transmit Interrupting Channel Reg */
-#define micr 0x46 /* Modem Interrupting Channel Register */
-
-#define gcr 0x4b /* Global configuration register */
-#define misr 0x4c /* Modem interrupt status register */
-
-#define rbusr 0x59
-#define tbusr 0x5a
-#define mbusr 0x5b
-
-#define eoir 0x60 /* End Of Interrupt Register */
-#define rdsr 0x62 /* Receive Data / Status Register */
-#define tdr 0x63 /* Transmit Data Register */
-#define svrr 0x67 /* Service Request Register */
-
-#define car 0x68 /* Channel Access Register */
-#define mir 0x69 /* Modem Interrupt Register */
-#define tir 0x6a /* Transmit Interrupt Register */
-#define rir 0x6b /* Receive Interrupt Register */
-#define msvr1 0x6c /* Modem Signal Value Register 1 */
-#define msvr2 0x6d /* Modem Signal Value Register 2 */
-#define psvr 0x6f /* Printer Signal Value Register */
-
-#define tbpr 0x72 /* Transmit Baud Rate Period Register */
-#define tcor 0x76 /* Transmit Clock Option Register */
-
-#define rbpr 0x78 /* Receive Baud Rate Period Register */
-#define rber 0x7a /* Receive Baud Rate Extension Register */
-#define rcor 0x7c /* Receive Clock Option Register */
-#define ppr 0x7e /* Prescalar Period Register */
-
-/* Misc registers used for forcing the 1400 out of its reset woes */
-#define airl 0x6d
-#define airm 0x6e
-#define airh 0x6f
-#define btcr 0x66
-#define mtcr 0x6c
-#define tber 0x74
-
-#endif /* #ifdef RTA */
/* Bit fields for particular registers */
diff --git a/drivers/char/rio/defaults.h b/drivers/char/rio/defaults.h
index 5b600c32ac02..d55c2f6a9877 100644
--- a/drivers/char/rio/defaults.h
+++ b/drivers/char/rio/defaults.h
@@ -45,13 +45,6 @@ static char *_rio_defaults_h_sccs = "@(#)defaults.h 1.1";
#define MILLISECOND (int) (1000/64) /* 15.625 low ticks */
#define SECOND (int) 15625 /* Low priority ticks */
-#ifdef RTA
-#define RX_LIMIT (ushort) 3
-#endif
-#ifdef HOST
-#define RX_LIMIT (ushort) 1
-#endif
-
#define LINK_TIMEOUT (int) (POLL_PERIOD / 2)
diff --git a/drivers/char/rio/link.h b/drivers/char/rio/link.h
index bfba5b0c033e..48d68ca7f825 100644
--- a/drivers/char/rio/link.h
+++ b/drivers/char/rio/link.h
@@ -102,30 +102,14 @@
/*
** LED stuff
*/
-#if defined(RTA)
-#define LED_OFF ((ushort) 0) /* LED off */
-#define LED_RED ((ushort) 1) /* LED Red */
-#define LED_GREEN ((ushort) 2) /* LED Green */
-#define LED_ORANGE ((ushort) 4) /* LED Orange */
-#define LED_1TO8_OPEN ((ushort) 1) /* Port 1->8 LED on */
-#define LED_9TO16_OPEN ((ushort) 2) /* Port 9->16 LED on */
-#define LED_SET_COLOUR(colour) (link->led = (colour))
-#define LED_OR_COLOUR(colour) (link->led |= (colour))
-#define LED_TIMEOUT(time) (link->led_timeout = RioTimePlus(RioTime(),(time)))
-#else
#define LED_SET_COLOUR(colour)
#define LED_OR_COLOUR(colour)
#define LED_TIMEOUT(time)
-#endif /* RTA */
struct LPB {
WORD link_number; /* Link Number */
Channel_ptr in_ch; /* Link In Channel */
Channel_ptr out_ch; /* Link Out Channel */
-#ifdef RTA
- uchar stat_led; /* Port open leds */
- uchar led; /* True, light led! */
-#endif
BYTE attached_serial[4]; /* Attached serial number */
BYTE attached_host_serial[4];
/* Serial number of Host who
@@ -144,30 +128,12 @@ struct LPB {
WORD WaitNoBoot; /* Secs to hold off booting */
PKT_ptr add_packet_list; /* Add packets to here */
PKT_ptr remove_packet_list; /* Send packets from here */
-#ifdef RTA
-#ifdef DCIRRUS
-#define QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1)
-#else
-#define QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1)
-#endif
- PKT_ptr_ptr rd_add; /* Add a new Packet here */
- Q_BUF_ptr rd_add_qb; /* Pointer to the add Q buf */
- PKT_ptr_ptr rd_add_st_qbb; /* Pointer to start of the Q's buf */
- PKT_ptr_ptr rd_add_end_qbb; /* Pointer to the end of the Q's buf */
- PKT_ptr_ptr rd_remove; /* Remove a Packet here */
- Q_BUF_ptr rd_remove_qb; /* Pointer to the remove Q buf */
- PKT_ptr_ptr rd_remove_st_qbb; /* Pointer to the start of the Q buf */
- PKT_ptr_ptr rd_remove_end_qbb; /* Pointer to the end of the Q buf */
- ushort pkts_in_q; /* Packets in queue */
-#endif
Channel_ptr lrt_fail_chan; /* Lrt's failure channel */
Channel_ptr ltt_fail_chan; /* Ltt's failure channel */
-#if defined (HOST) || defined (INKERNEL)
/* RUP structure for HOST to driver communications */
struct RUP rup;
-#endif
struct RUP link_rup; /* RUP for the link (POLL,
topology etc.) */
WORD attached_link; /* Number of attached link */
diff --git a/drivers/char/rio/list.h b/drivers/char/rio/list.h
index 36aad4c9cb3a..79b853140ae5 100644
--- a/drivers/char/rio/list.h
+++ b/drivers/char/rio/list.h
@@ -44,8 +44,6 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9";
#define PKT_IN_USE 0x1
-#ifdef INKERNEL
-
#define ZERO_PTR (ushort) 0x8000
#define CaD PortP->Caddr
@@ -54,143 +52,5 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9";
** to by the TxAdd pointer has PKT_IN_USE clear in its address.
*/
-#ifndef linux
-#if defined( MIPS ) && !defined( MIPSEISA )
-/* May the shoes of the Devil dance on your grave for creating this */
-#define can_add_transmit(PacketP,PortP) \
- (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
- & (PKT_IN_USE<<2)))
-
-#elif defined(MIPSEISA) || defined(nx6000) || \
- defined(drs6000) || defined(UWsparc)
-
-#define can_add_transmit(PacketP,PortP) \
- (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
- & PKT_IN_USE))
-
-#else
-#define can_add_transmit(PacketP,PortP) \
- (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \
- & PKT_IN_USE))
-#endif
-
-/*
-** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
-** and then move the TxAdd pointer along one position to point to the next
-** packet pointer. You must wrap the pointer from the end back to the start.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-# define add_transmit(PortP) \
- WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\
- if (PortP->TxAdd == PortP->TxEnd)\
- PortP->TxAdd = PortP->TxStart;\
- else\
- PortP->TxAdd++;\
- WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd));
-#elif defined(AIX)
-# define add_transmit(PortP) \
- {\
- register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\
- WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\
- if (PortP->TxAddO == PortP->TxEndO )\
- PortP->TxAddO = PortP->TxStartO;\
- else\
- PortP->TxAddO += sizeof(ushort);\
- WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\
- }
-#else
-# define add_transmit(PortP) \
- *PortP->TxAdd |= PKT_IN_USE;\
- if (PortP->TxAdd == PortP->TxEnd)\
- PortP->TxAdd = PortP->TxStart;\
- else\
- PortP->TxAdd++;\
- PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd);
-#endif
-
-/*
-** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set
-** for the next packet on the queue. It will also set PacketP to point to the
-** relevant packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
-** then can_remove_receive() returns 0.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-# define can_remove_receive(PacketP,PortP) \
- ((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \
- (PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0)
-#elif defined(AIX)
-# define can_remove_receive(PacketP,PortP) \
- ((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \
- (PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0)
-#else
-# define can_remove_receive(PacketP,PortP) \
- ((*PortP->RxRemove & PKT_IN_USE) ? \
- (PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0)
-#endif
-
-
-/*
-** Will God see it within his heart to forgive us for this thing that
-** we have created? To remove a packet from the receive queue you clear
-** its PKT_IN_USE bit, and then bump the pointers. Once the pointers
-** get to the end, they must be wrapped back to the start.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-# define remove_receive(PortP) \
- WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\
- if (PortP->RxRemove == PortP->RxEnd)\
- PortP->RxRemove = PortP->RxStart;\
- else\
- PortP->RxRemove++;\
- WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove));
-#elif defined(AIX)
-# define remove_receive(PortP) \
- {\
- register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\
- WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\
- if (PortP->RxRemoveO == PortP->RxEndO)\
- PortP->RxRemoveO = PortP->RxStartO;\
- else\
- PortP->RxRemoveO += sizeof(ushort);\
- WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\
- }
-#else
-# define remove_receive(PortP) \
- *PortP->RxRemove &= ~PKT_IN_USE;\
- if (PortP->RxRemove == PortP->RxEnd)\
- PortP->RxRemove = PortP->RxStart;\
- else\
- PortP->RxRemove++;\
- PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove);
-#endif
-#endif
-
-
-#else /* !IN_KERNEL */
-
-#define ZERO_PTR NULL
-
-
-#ifdef HOST
-/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE)) */
-#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\
- if (phb->tx_remove == phb->tx_end)\
- phb->tx_remove = phb->tx_start;\
- else\
- phb->tx_remove++;
-#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE)
-#define add_receive(pkt,phb) *phb->rx_add = pkt;\
- *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\
- if (phb->rx_add == phb->rx_end)\
- phb->rx_add = phb->rx_start;\
- else\
- phb->rx_add++;
-#endif
-#endif
-
-#ifdef RTA
-#define splx(oldspl) if ((oldspl) == 0) spl0()
-#endif
-
#endif /* ifndef _list.h */
/*********** end of file ***********/
diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h
index fe4e00567065..e24acc1d1844 100644
--- a/drivers/char/rio/parmmap.h
+++ b/drivers/char/rio/parmmap.h
@@ -78,14 +78,9 @@ struct PARM_MAP {
WORD idle_count; /* Idle time counter */
WORD busy_count; /* Busy counter */
WORD idle_control; /* Control Idle Process */
-#if defined(HOST) || defined(INKERNEL)
WORD tx_intr; /* TX interrupt pending */
WORD rx_intr; /* RX interrupt pending */
WORD rup_intr; /* RUP interrupt pending */
-#endif
-#if defined(RTA)
- WORD dying_count; /* Count of processes dead */
-#endif
};
#endif
diff --git a/drivers/char/rio/phb.h b/drivers/char/rio/phb.h
index 3baebf8513af..2663ca0306e2 100644
--- a/drivers/char/rio/phb.h
+++ b/drivers/char/rio/phb.h
@@ -44,17 +44,6 @@
#endif
- /*************************************************
- * Set the LIMIT values.
- ************************************************/
-#ifdef RTA
-#define RX_LIMIT (ushort) 3
-#endif
-#ifdef HOST
-#define RX_LIMIT (ushort) 1
-#endif
-
-
/*************************************************
* Handshake asserted. Deasserted by the LTT(s)
************************************************/
@@ -69,11 +58,7 @@
/*************************************************
* Maximum number of PHB's
************************************************/
-#if defined (HOST) || defined (INKERNEL)
#define MAX_PHB ((ushort) 128) /* range 0-127 */
-#else
-#define MAX_PHB ((ushort) 8) /* range 0-7 */
-#endif
/*************************************************
* Defines for the mode fields
@@ -139,141 +124,23 @@
* the start. The pointer tx_add points to a SPACE to put a Packet.
* The pointer tx_remove points to the next Packet to remove
*************************************************************************/
-#ifndef INKERNEL
-#define src_unit u2.s2.unit
-#define src_port u2.s2.port
-#define dest_unit u1.s1.unit
-#define dest_port u1.s1.port
-#endif
-#ifdef HOST
-#define tx_start u3.s1.tx_start_ptr_ptr
-#define tx_add u3.s1.tx_add_ptr_ptr
-#define tx_end u3.s1.tx_end_ptr_ptr
-#define tx_remove u3.s1.tx_remove_ptr_ptr
-#define rx_start u4.s1.rx_start_ptr_ptr
-#define rx_add u4.s1.rx_add_ptr_ptr
-#define rx_end u4.s1.rx_end_ptr_ptr
-#define rx_remove u4.s1.rx_remove_ptr_ptr
-#endif
typedef struct PHB PHB;
struct PHB {
-#ifdef RTA
- ushort port;
-#endif
-#ifdef INKERNEL
WORD source;
-#else
- union {
- ushort source; /* Complete source */
- struct {
- unsigned char unit; /* Source unit */
- unsigned char port; /* Source port */
- } s2;
- } u2;
-#endif
WORD handshake;
WORD status;
NUMBER timeout; /* Maximum of 1.9 seconds */
WORD link; /* Send down this link */
-#ifdef INKERNEL
WORD destination;
-#else
- union {
- ushort destination; /* Complete destination */
- struct {
- unsigned char unit; /* Destination unit */
- unsigned char port; /* Destination port */
- } s1;
- } u1;
-#endif
-#ifdef RTA
- ushort tx_pkts_added;
- ushort tx_pkts_removed;
- Q_BUF_ptr tx_q_start; /* Start of the Q list chain */
- short num_tx_q_bufs; /* Number of Q buffers in the chain */
- PKT_ptr_ptr tx_add; /* Add a new Packet here */
- Q_BUF_ptr tx_add_qb; /* Pointer to the add Q buf */
- PKT_ptr_ptr tx_add_st_qbb; /* Pointer to start of the Q's buf */
- PKT_ptr_ptr tx_add_end_qbb; /* Pointer to the end of the Q's buf */
- PKT_ptr_ptr tx_remove; /* Remove a Packet here */
- Q_BUF_ptr tx_remove_qb; /* Pointer to the remove Q buf */
- PKT_ptr_ptr tx_remove_st_qbb; /* Pointer to the start of the Q buf */
- PKT_ptr_ptr tx_remove_end_qbb; /* Pointer to the end of the Q buf */
-#endif
-#ifdef INKERNEL
PKT_ptr_ptr tx_start;
PKT_ptr_ptr tx_end;
PKT_ptr_ptr tx_add;
PKT_ptr_ptr tx_remove;
-#endif
-#ifdef HOST
- union {
- struct {
- PKT_ptr_ptr tx_start_ptr_ptr;
- PKT_ptr_ptr tx_end_ptr_ptr;
- PKT_ptr_ptr tx_add_ptr_ptr;
- PKT_ptr_ptr tx_remove_ptr_ptr;
- } s1;
- struct {
- ushort *tx_start_ptr;
- ushort *tx_end_ptr;
- ushort *tx_add_ptr;
- ushort *tx_remove_ptr;
- } s2;
- } u3;
-#endif
-#ifdef RTA
- ushort rx_pkts_added;
- ushort rx_pkts_removed;
- Q_BUF_ptr rx_q_start; /* Start of the Q list chain */
- short num_rx_q_bufs; /* Number of Q buffers in the chain */
- PKT_ptr_ptr rx_add; /* Add a new Packet here */
- Q_BUF_ptr rx_add_qb; /* Pointer to the add Q buf */
- PKT_ptr_ptr rx_add_st_qbb; /* Pointer to start of the Q's buf */
- PKT_ptr_ptr rx_add_end_qbb; /* Pointer to the end of the Q's buf */
- PKT_ptr_ptr rx_remove; /* Remove a Packet here */
- Q_BUF_ptr rx_remove_qb; /* Pointer to the remove Q buf */
- PKT_ptr_ptr rx_remove_st_qbb; /* Pointer to the start of the Q buf */
- PKT_ptr_ptr rx_remove_end_qbb; /* Pointer to the end of the Q buf */
-#endif
-#ifdef INKERNEL
PKT_ptr_ptr rx_start;
PKT_ptr_ptr rx_end;
PKT_ptr_ptr rx_add;
PKT_ptr_ptr rx_remove;
-#endif
-#ifdef HOST
- union {
- struct {
- PKT_ptr_ptr rx_start_ptr_ptr;
- PKT_ptr_ptr rx_end_ptr_ptr;
- PKT_ptr_ptr rx_add_ptr_ptr;
- PKT_ptr_ptr rx_remove_ptr_ptr;
- } s1;
- struct {
- ushort *rx_start_ptr;
- ushort *rx_end_ptr;
- ushort *rx_add_ptr;
- ushort *rx_remove_ptr;
- } s2;
- } u4;
-#endif
-
-#ifdef RTA /* some fields for the remotes */
- ushort flush_count; /* Count of write flushes */
- ushort txmode; /* Modes for tx */
- ushort rxmode; /* Modes for rx */
- ushort portmode; /* Generic modes */
- ushort column; /* TAB3 column count */
- ushort tx_subscript; /* (TX) Subscript into data field */
- ushort rx_subscript; /* (RX) Subscript into data field */
- PKT_ptr rx_incomplete; /* Hold an incomplete packet here */
- ushort modem_bits; /* Modem bits to mask */
- ushort lastModem; /* Modem control lines. */
- ushort addr; /* Address for sub commands */
- ushort MonitorTstate; /* TRUE if monitoring tstop */
-#endif
};
diff --git a/drivers/char/rio/pkt.h b/drivers/char/rio/pkt.h
index 882fd429ac2e..7011e52e82db 100644
--- a/drivers/char/rio/pkt.h
+++ b/drivers/char/rio/pkt.h
@@ -70,39 +70,12 @@
#define CONTROL_DATA_WNDW (DATA_WNDW << 8)
struct PKT {
-#ifdef INKERNEL
BYTE dest_unit; /* Destination Unit Id */
BYTE dest_port; /* Destination POrt */
BYTE src_unit; /* Source Unit Id */
BYTE src_port; /* Source POrt */
-#else
- union {
- ushort destination; /* Complete destination */
- struct {
- unsigned char unit; /* Destination unit */
- unsigned char port; /* Destination port */
- } s1;
- } u1;
- union {
- ushort source; /* Complete source */
- struct {
- unsigned char unit; /* Source unit */
- unsigned char port; /* Source port */
- } s2;
- } u2;
-#endif
-#ifdef INKERNEL
BYTE len;
BYTE control;
-#else
- union {
- ushort control;
- struct {
- unsigned char len;
- unsigned char control;
- } s3;
- } u3;
-#endif
BYTE data[PKT_MAX_DATA_LEN];
/* Actual data :-) */
WORD csum; /* C-SUM */
diff --git a/drivers/char/rio/qbuf.h b/drivers/char/rio/qbuf.h
index acd9e8e5307d..391ffc335535 100644
--- a/drivers/char/rio/qbuf.h
+++ b/drivers/char/rio/qbuf.h
@@ -46,11 +46,7 @@ static char *_rio_qbuf_h_sccs = "@(#)qbuf.h 1.1";
-#ifdef HOST
-#define PKTS_PER_BUFFER 1
-#else
#define PKTS_PER_BUFFER (220 / PKT_LENGTH)
-#endif
typedef struct Q_BUF Q_BUF;
struct Q_BUF {
diff --git a/drivers/char/rio/riotypes.h b/drivers/char/rio/riotypes.h
index 9b67e2468bec..46084d5c7e98 100644
--- a/drivers/char/rio/riotypes.h
+++ b/drivers/char/rio/riotypes.h
@@ -43,9 +43,6 @@
#endif
#endif
-#ifdef INKERNEL
-
-#if !defined(MIPSAT)
typedef unsigned short NUMBER_ptr;
typedef unsigned short WORD_ptr;
typedef unsigned short BYTE_ptr;
@@ -65,69 +62,6 @@ typedef unsigned short RUP_ptr;
typedef unsigned short short_ptr;
typedef unsigned short u_short_ptr;
typedef unsigned short ushort_ptr;
-#else
-/* MIPSAT types */
-typedef char RIO_POINTER[8];
-typedef RIO_POINTER NUMBER_ptr;
-typedef RIO_POINTER WORD_ptr;
-typedef RIO_POINTER BYTE_ptr;
-typedef RIO_POINTER char_ptr;
-typedef RIO_POINTER Channel_ptr;
-typedef RIO_POINTER FREE_LIST_ptr_ptr;
-typedef RIO_POINTER FREE_LIST_ptr;
-typedef RIO_POINTER LPB_ptr;
-typedef RIO_POINTER Process_ptr;
-typedef RIO_POINTER PHB_ptr;
-typedef RIO_POINTER PKT_ptr;
-typedef RIO_POINTER PKT_ptr_ptr;
-typedef RIO_POINTER Q_BUF_ptr;
-typedef RIO_POINTER Q_BUF_ptr_ptr;
-typedef RIO_POINTER ROUTE_STR_ptr;
-typedef RIO_POINTER RUP_ptr;
-typedef RIO_POINTER short_ptr;
-typedef RIO_POINTER u_short_ptr;
-typedef RIO_POINTER ushort_ptr;
-#endif
-
-#else /* not INKERNEL */
-typedef unsigned char BYTE;
-typedef unsigned short WORD;
-typedef unsigned long DWORD;
-typedef short NUMBER;
-typedef short *NUMBER_ptr;
-typedef unsigned short *WORD_ptr;
-typedef unsigned char *BYTE_ptr;
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef unsigned char u_char;
-typedef unsigned short u_short;
-typedef unsigned int u_int;
-typedef unsigned long u_long;
-typedef unsigned short ERROR;
-typedef unsigned long ID;
-typedef char *char_ptr;
-typedef Channel *Channel_ptr;
-typedef struct FREE_LIST *FREE_LIST_ptr;
-typedef struct FREE_LIST **FREE_LIST_ptr_ptr;
-typedef struct LPB *LPB_ptr;
-typedef struct Process *Process_ptr;
-typedef struct PHB *PHB_ptr;
-typedef struct PKT *PKT_ptr;
-typedef struct PKT **PKT_ptr_ptr;
-typedef struct Q_BUF *Q_BUF_ptr;
-typedef struct Q_BUF **Q_BUF_ptr_ptr;
-typedef struct ROUTE_STR *ROUTE_STR_ptr;
-typedef struct RUP *RUP_ptr;
-typedef short *short_ptr;
-typedef u_short *u_short_ptr;
-typedef ushort *ushort_ptr;
-typedef struct PKT PKT;
-typedef struct LPB LPB;
-typedef struct RUP RUP;
-#endif
-
#endif /* __riotypes__ */
diff --git a/drivers/char/rio/rup.h b/drivers/char/rio/rup.h
index 8d44fec91dd5..f74f67c6f702 100644
--- a/drivers/char/rio/rup.h
+++ b/drivers/char/rio/rup.h
@@ -43,12 +43,7 @@
#endif
#endif
-#if defined( HOST ) || defined( INKERNEL )
#define MAX_RUP ((short) 16)
-#endif
-#ifdef RTA
-#define MAX_RUP ((short) 1)
-#endif
#define PKTS_PER_RUP ((short) 2) /* They are always used in pairs */
diff --git a/drivers/char/rio/sam.h b/drivers/char/rio/sam.h
index 31494054b213..6f754e19015d 100644
--- a/drivers/char/rio/sam.h
+++ b/drivers/char/rio/sam.h
@@ -43,10 +43,6 @@
#endif
-#if !defined( HOST ) && !defined( INKERNEL )
-#define RTA 1
-#endif
-
#define NUM_FREE_LIST_UNITS 500
#ifndef FALSE
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 0949dcef0697..7edc6a4dbdc4 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -433,7 +433,7 @@ static void rp_do_receive(struct r_port *info,
count += ToRecv;
}
/* Push the data up to the tty layer */
- ld->receive_buf(tty, cbuf, fbuf, count);
+ ld->receive_buf(tty, chead, fhead, count);
done:
tty_ldisc_deref(ld);
}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 64bf89cb574f..c2490e270f1f 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -931,7 +931,7 @@ static int sx_set_real_termios (void *ptr)
case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
default:
- printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);
+ printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
break;
}
@@ -958,7 +958,7 @@ static int sx_set_real_termios (void *ptr)
} else {
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+ sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
port->gs.tty->termios->c_iflag,
I_OTHER(port->gs.tty));
@@ -973,7 +973,7 @@ static int sx_set_real_termios (void *ptr)
} else {
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+ sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
port->gs.tty->termios->c_oflag,
O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index eb8b5be4e249..076e07c1da38 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty)
static void tty_buffer_init(struct tty_struct *tty)
{
+ spin_lock_init(&tty->buf.lock);
tty->buf.head = NULL;
tty->buf.tail = NULL;
tty->buf.free = NULL;
@@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
p->used = 0;
p->size = size;
p->next = NULL;
+ p->active = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
/* printk("Flip create %p\n", p); */
@@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
- struct tty_buffer *b = tty->buf.tail, *n;
- int left = 0;
+ struct tty_buffer *b, *n;
+ int left;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
- if(b != NULL)
+ if ((b = tty->buf.tail) != NULL) {
left = b->size - b->used;
- if(left >= size)
- return size;
- /* This is the slow path - looking for new buffers to use */
- n = tty_buffer_find(tty, size);
- if(n == NULL)
- return left;
- if(b != NULL)
- b->next = n;
- else
- tty->buf.head = n;
- tty->buf.tail = n;
+ b->active = 1;
+ } else
+ left = 0;
+
+ if (left < size) {
+ /* This is the slow path - looking for new buffers to use */
+ if ((n = tty_buffer_find(tty, size)) != NULL) {
+ if (b != NULL) {
+ b->next = n;
+ b->active = 0;
+ } else
+ tty->buf.head = n;
+ tty->buf.tail = n;
+ n->active = 1;
+ } else
+ size = left;
+ }
+
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
@@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
{
int space = tty_buffer_request_room(tty, size);
- struct tty_buffer *tb = tty->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
- tb->used += space;
+ if (likely(space)) {
+ struct tty_buffer *tb = tty->buf.tail;
+ *chars = tb->char_buf_ptr + tb->used;
+ memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+ tb->used += space;
+ }
return space;
}
@@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
{
int space = tty_buffer_request_room(tty, size);
- struct tty_buffer *tb = tty->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- *flags = tb->flag_buf_ptr + tb->used;
- tb->used += space;
+ if (likely(space)) {
+ struct tty_buffer *tb = tty->buf.tail;
+ *chars = tb->char_buf_ptr + tb->used;
+ *flags = tb->flag_buf_ptr + tb->used;
+ tb->used += space;
+ }
return space;
}
@@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_)
schedule_delayed_work(&tty->buf.work, 1);
goto out;
}
- spin_lock_irqsave(&tty->read_lock, flags);
- while((tbuf = tty->buf.head) != NULL) {
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ while((tbuf = tty->buf.head) != NULL && !tbuf->active) {
tty->buf.head = tbuf->next;
if (tty->buf.head == NULL)
tty->buf.tail = NULL;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
/* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
disc->receive_buf(tty, tbuf->char_buf_ptr,
tbuf->flag_buf_ptr,
tbuf->used);
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&tty->buf.lock, flags);
tty_buffer_free(tty, tbuf);
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
out:
tty_ldisc_deref(disc);
}
@@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate);
void tty_flip_buffer_push(struct tty_struct *tty)
{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ if (tty->buf.tail != NULL)
+ tty->buf.tail->active = 0;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+
if (tty->low_latency)
flush_to_ldisc((void *) tty);
else
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
index 951764614ebf..7a4dfb95d087 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -25,6 +25,7 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -181,11 +182,14 @@ static int __init watchdog_init(void)
{
int ret;
+ if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog"))
+ return -EBUSY;
+
ret = register_reboot_notifier(&epx_c3_notifier);
if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier "
"(err=%d)\n", ret);
- return ret;
+ goto out;
}
ret = misc_register(&epx_c3_miscdev);
@@ -193,18 +197,23 @@ static int __init watchdog_init(void)
printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
"(err=%d)\n", WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&epx_c3_notifier);
- return ret;
+ goto out;
}
printk(banner);
return 0;
+
+out:
+ release_region(EPXC3_WATCHDOG_CTL_REG, 2);
+ return ret;
}
static void __exit watchdog_exit(void)
{
misc_deregister(&epx_c3_miscdev);
unregister_reboot_notifier(&epx_c3_notifier);
+ release_region(EPXC3_WATCHDOG_CTL_REG, 2);
}
module_init(watchdog_init);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 4819e7fc00dd..d94331c1e5b0 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -46,7 +46,7 @@ config EDAC_MM_EDAC
config EDAC_AMD76X
tristate "AMD 76x (760, 762, 768)"
- depends on EDAC_MM_EDAC && PCI
+ depends on EDAC_MM_EDAC && PCI && X86_32
help
Support for error detection and correction on the AMD 76x
series of chipsets used with the Athlon processor.
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 770a5a633079..c454ded2b060 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -1039,10 +1039,10 @@ MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
static struct pci_driver e752x_driver = {
- name: BS_MOD_STR,
- probe: e752x_init_one,
- remove: __devexit_p(e752x_remove_one),
- id_table: e752x_pci_tbl,
+ .name = BS_MOD_STR,
+ .probe = e752x_init_one,
+ .remove = __devexit_p(e752x_remove_one),
+ .id_table = e752x_pci_tbl,
};
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 4be9bd0a1267..b10ee4698b1d 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -14,7 +14,6 @@
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 1c81174595b3..d633081fa4c5 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -52,9 +52,9 @@ config IDE
if IDE
-config IDE_MAX_HWIFS
+config IDE_MAX_HWIFS
int "Max IDE interfaces"
- depends on ALPHA || SUPERH
+ depends on ALPHA || SUPERH || IA64
default 4
help
This is the maximum number of IDE hardware interfaces that will
@@ -162,8 +162,8 @@ config BLK_DEV_IDECS
tristate "PCMCIA IDE support"
depends on PCMCIA
help
- Support for outboard IDE disks, tape drives, and CD-ROM drives
- connected through a PCMCIA card.
+ Support for Compact Flash cards, outboard IDE disks, tape drives,
+ and CD-ROM drives connected through a PCMCIA card.
config BLK_DEV_IDECD
tristate "Include IDE/ATAPI CDROM support"
@@ -267,7 +267,7 @@ config IDE_TASK_IOCTL
help
This is a direct raw access to the media. It is a complex but
elegant solution to test and validate the domain of the hardware and
- perform below the driver data recover if needed. This is the most
+ perform below the driver data recovery if needed. This is the most
basic form of media-forensics.
If you are unsure, say N here.
@@ -525,7 +525,7 @@ config BLK_DEV_CS5520
tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
depends on EXPERIMENTAL
help
- Include support for PIO tuning an virtual DMA on the Cyrix MediaGX
+ Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
5510/5520 chipset. This will automatically be detected and
configured if found.
@@ -662,7 +662,7 @@ config PDC202XX_BURST
It was originally designed for the PDC20246/Ultra33, whose BIOS will
only setup UDMA on the first two PDC20246 cards. It has also been
- used succesfully on a PDC20265/Ultra100, allowing use of UDMA modes
+ used successfully on a PDC20265/Ultra100, allowing use of UDMA modes
when the PDC20265 BIOS has been disabled (for faster boot up).
Please read the comments at the top of
@@ -673,13 +673,6 @@ config PDC202XX_BURST
config BLK_DEV_PDC202XX_NEW
tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
-# FIXME - probably wants to be one for old and for new
-config PDC202XX_FORCE
- bool "Enable controller even if disabled by BIOS"
- depends on BLK_DEV_PDC202XX_NEW
- help
- Enable the PDC202xx controller even if it has been disabled in the BIOS setup.
-
config BLK_DEV_SVWKS
tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
help
@@ -722,7 +715,7 @@ config BLK_DEV_SIS5513
config BLK_DEV_SLC90E66
tristate "SLC90E66 chipset support"
help
- This driver ensures (U)DMA support for Victroy66 SouthBridges for
+ This driver ensures (U)DMA support for Victory66 SouthBridges for
SMsC with Intel NorthBridges. This is an Ultra66 based chipset.
The nice thing about it is that you can mix Ultra/DMA/PIO devices
and it will handle timing cycles. Since this is an improved
@@ -1060,7 +1053,7 @@ config IDEDMA_IVB
in that mode with an 80c ribbon.
If you are experiencing compatibility or performance problems, you
- MAY try to answering Y here. However, it does not necessarily solve
+ MAY try to answer Y here. However, it does not necessarily solve
any of your problems, it could even cause more of them.
It is normally safe to answer Y; however, the default is N.
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index ca25f9e3d0f4..6c60a9d2afd8 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive)
ide_id_has_flush_cache_ext(id));
printk(KERN_INFO "%s: cache flushes %ssupported\n",
- drive->name, barrier ? "" : "not");
+ drive->name, barrier ? "" : "not ");
if (barrier) {
ordered = QUEUE_ORDERED_DRAIN_FLUSH;
@@ -889,11 +889,7 @@ static void idedisk_setup (ide_drive_t *drive)
if (drive->id_read == 0)
return;
- /*
- * CompactFlash cards and their brethern look just like hard drives
- * to us, but they are removable and don't have a doorlock mechanism.
- */
- if (drive->removable && !(drive->is_flash)) {
+ if (drive->removable) {
/*
* Removable disks (eg. SYQUEST); ignore 'WD' drives
*/
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 8d50df4526a4..c01615dec202 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,8 +55,8 @@
#include <asm/io.h>
#include <asm/bitops.h>
-int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
- int nr_sectors)
+static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, int nr_sectors)
{
int ret = 1;
@@ -91,7 +91,6 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
return ret;
}
-EXPORT_SYMBOL(__ide_end_request);
/**
* ide_end_request - complete an IDE I/O
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index af7af958ab3e..b72dde70840a 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -1243,6 +1243,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
*/
if (stat == 0xff)
return -ENODEV;
+ touch_softlockup_watchdog();
}
return -EBUSY;
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index e7425546b4b1..427d1c204174 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -125,45 +125,6 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
}
/**
- * drive_is_flashcard - check for compact flash
- * @drive: drive to check
- *
- * CompactFlash cards and their brethern pretend to be removable
- * hard disks, except:
- * (1) they never have a slave unit, and
- * (2) they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting
- * appropriate config bits.
- *
- * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
- * devices, so in linux 2.3.x we should change this to just treat all
- * PCMCIA drives this way, and get rid of the model-name tests below
- * (too big of an interface change for 2.4.x).
- * At that time, we might also consider parameterizing the timeouts and
- * retries, since these are MUCH faster than mechanical drives. -M.Lord
- */
-
-static inline int drive_is_flashcard (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
-
- if (drive->removable) {
- if (id->config == 0x848a) return 1; /* CompactFlash */
- if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */
- || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */
- || !strncmp(id->model, "SunDisk SDCFB", 13) /* old SanDisk */
- || !strncmp(id->model, "SanDisk SDCFB", 13) /* SanDisk */
- || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */
- || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */
- || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */
- {
- return 1; /* yes, it is a flash memory card */
- }
- }
- return 0; /* no, it is not a flash memory card */
-}
-
-/**
* do_identify - identify a drive
* @drive: drive to identify
* @cmd: command used
@@ -278,13 +239,17 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
/*
* Not an ATAPI device: looks like a "regular" hard disk
*/
- if (id->config & (1<<7))
+
+ /*
+ * 0x848a = CompactFlash device
+ * These are *not* removable in Linux definition of the term
+ */
+
+ if ((id->config != 0x848a) && (id->config & (1<<7)))
drive->removable = 1;
- if (drive_is_flashcard(drive))
- drive->is_flash = 1;
drive->media = ide_disk;
- printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+ printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
QUIRK_LIST(drive);
return;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index afeb02bbb722..b2cc43702f65 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -242,7 +242,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
drive->using_dma = 0;
- drive->is_flash = 0;
drive->vdma = 0;
INIT_LIST_HEAD(&drive->list);
init_completion(&drive->gendev_rel_comp);
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index a21b1e11eef4..c743e68c33aa 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -262,6 +262,21 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
else
pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+ /* These are necessary to get AEC6280 Macintosh cards to work */
+ if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
+ (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
+ u8 reg49h = 0, reg4ah = 0;
+ /* Clear reset and test bits. */
+ pci_read_config_byte(dev, 0x49, &reg49h);
+ pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
+ /* Enable chip interrupt output. */
+ pci_read_config_byte(dev, 0x4a, &reg4ah);
+ pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
+ /* Enable burst mode. */
+ pci_read_config_byte(dev, 0x4a, &reg4ah);
+ pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
+ }
+
return dev->irq;
}
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 7b589d948bf9..940bdd4c5784 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1288,6 +1288,10 @@ static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
goto init_hpt37X_done;
}
}
+ if (!pci_get_drvdata(dev)) {
+ printk("No Clock Stabilization!!!\n");
+ return;
+ }
pll_recal:
if (adjust & 1)
pll -= (adjust >> 1);
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 108fda83fea4..38f41b377ff6 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -733,7 +733,7 @@ static void __devinit it8212_disable_raid(struct pci_dev *dev)
pci_write_config_dword(dev,0x4C, 0x02040204);
pci_write_config_byte(dev, 0x42, 0x36);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
}
static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index fe06ebb0e5bf..acd63173199b 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -420,9 +420,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.init_hwif = init_hwif_pdc202new,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
},{ /* 3 */
.name = "PDC20271",
@@ -447,9 +444,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.init_hwif = init_hwif_pdc202new,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
},{ /* 6 */
.name = "PDC20277",
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index ad9d95817f95..6f8f8645b02c 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -786,9 +786,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 16,
},{ /* 1 */
@@ -799,9 +796,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
.flags = IDEPCI_FLAG_FORCE_PDC,
@@ -813,9 +807,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
},{ /* 3 */
@@ -826,9 +817,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
.flags = IDEPCI_FLAG_FORCE_PDC,
@@ -840,9 +828,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index b3e77df63cef..e9b83e1a3028 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -135,6 +135,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
case PCI_DEVICE_ID_INTEL_ICH6_19:
case PCI_DEVICE_ID_INTEL_ICH7_21:
case PCI_DEVICE_ID_INTEL_ESB2_18:
+ case PCI_DEVICE_ID_INTEL_ICH8_6:
mode = 3;
break;
/* UDMA 66 capable */
@@ -449,6 +450,7 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char
case PCI_DEVICE_ID_INTEL_ICH6_19:
case PCI_DEVICE_ID_INTEL_ICH7_21:
case PCI_DEVICE_ID_INTEL_ESB2_18:
+ case PCI_DEVICE_ID_INTEL_ICH8_6:
{
unsigned int extra = 0;
pci_read_config_dword(dev, 0x54, &extra);
@@ -575,6 +577,7 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
/* 21 */ DECLARE_PIIX_DEV("ICH7"),
/* 22 */ DECLARE_PIIX_DEV("ICH4"),
/* 23 */ DECLARE_PIIX_DEV("ESB2"),
+ /* 24 */ DECLARE_PIIX_DEV("ICH8M"),
};
/**
@@ -651,6 +654,7 @@ static struct pci_device_id piix_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 24},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 1b85ce166af8..11fe537e2f6f 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -216,7 +216,7 @@ struct Layer1 {
#define GROUP_TEI 127
#define TEI_SAPI 63
#define CTRL_SAPI 0
-#define PACKET_NOACK 250
+#define PACKET_NOACK 7
/* Layer2 Flags */
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 3314a5a19854..94c9afb7017c 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -71,14 +71,14 @@ int sc_ioctl(int card, scs_ioctl *data)
/*
* Get the SRec from user space
*/
- if (copy_from_user(srec, data->dataptr, sizeof(srec))) {
+ if (copy_from_user(srec, data->dataptr, SCIOC_SRECSIZE)) {
kfree(rcvmsg);
kfree(srec);
return -EFAULT;
}
status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
- 0, sizeof(srec), srec, rcvmsg, SAR_TIMEOUT);
+ 0, SCIOC_SRECSIZE, srec, rcvmsg, SAR_TIMEOUT);
kfree(rcvmsg);
kfree(srec);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 653d4dcbee23..d05e3125d298 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1024,7 +1024,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
rdev-> sb_size = (rdev->sb_size | bmask)+1;
if (refdev == 0)
- return 1;
+ ret = 1;
else {
__u64 ev1, ev2;
struct mdp_superblock_1 *refsb =
@@ -1044,7 +1044,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
ev2 = le64_to_cpu(refsb->events);
if (ev1 > ev2)
- return 1;
+ ret = 1;
+ else
+ ret = 0;
}
if (minor_version)
rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2;
@@ -1058,7 +1060,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
if (le32_to_cpu(sb->size) > rdev->size*2)
return -EINVAL;
- return 0;
+ return ret;
}
static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
@@ -1081,7 +1083,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->size = le64_to_cpu(sb->size)/2;
mddev->events = le64_to_cpu(sb->events);
mddev->bitmap_offset = 0;
- mddev->default_bitmap_offset = 1024;
+ mddev->default_bitmap_offset = 1024 >> 9;
mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
memcpy(mddev->uuid, sb->set_uuid, 16);
@@ -1162,7 +1164,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors);
sb->raid_disks = cpu_to_le32(mddev->raid_disks);
- sb->size = cpu_to_le64(mddev->size);
+ sb->size = cpu_to_le64(mddev->size<<1);
if (mddev->bitmap && mddev->bitmap_file == NULL) {
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
@@ -2942,6 +2944,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
info.ctime = mddev->ctime;
info.level = mddev->level;
info.size = mddev->size;
+ if (info.size != mddev->size) /* overflow */
+ info.size = -1;
info.nr_disks = nr;
info.raid_disks = mddev->raid_disks;
info.md_minor = mddev->md_minor;
@@ -3523,7 +3527,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
)
return -EINVAL;
/* Check there is only one change */
- if (mddev->size != info->size) cnt++;
+ if (info->size >= 0 && mddev->size != info->size) cnt++;
if (mddev->raid_disks != info->raid_disks) cnt++;
if (mddev->layout != info->layout) cnt++;
if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) cnt++;
@@ -3540,7 +3544,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
else
return mddev->pers->reconfig(mddev, info->layout, -1);
}
- if (mddev->size != info->size)
+ if (info->size >= 0 && mddev->size != info->size)
rv = update_size(mddev, info->size);
if (mddev->raid_disks != info->raid_disks)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index d03f99cf4b7d..678f4dbbea1d 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -372,7 +372,7 @@ out_free_conf:
kfree(conf);
mddev->private = NULL;
out:
- return 1;
+ return -ENOMEM;
}
static int raid0_stop (mddev_t *mddev)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 9130d051b474..ab90a6d12020 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -565,6 +565,8 @@ rb_out:
if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+ else
+ disk = -1;
rcu_read_unlock();
return disk;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 25976bfb6f9c..2dba305daf3c 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -350,7 +350,8 @@ static void shrink_stripes(raid5_conf_t *conf)
while (drop_one_stripe(conf))
;
- kmem_cache_destroy(conf->slab_cache);
+ if (conf->slab_cache)
+ kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL;
}
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index ed2abb2e2e2d..cd477ebf2ee4 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -366,7 +366,8 @@ static void shrink_stripes(raid6_conf_t *conf)
while (drop_one_stripe(conf))
;
- kmem_cache_destroy(conf->slab_cache);
+ if (conf->slab_cache)
+ kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL;
}
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
index 90628562851e..184974cc734d 100644
--- a/drivers/message/i2o/core.h
+++ b/drivers/message/i2o/core.h
@@ -60,4 +60,7 @@ extern void i2o_iop_remove(struct i2o_controller *);
#define I2O_IN_PORT 0x40
#define I2O_OUT_PORT 0x44
+/* Motorola/Freescale specific register offset */
+#define I2O_MOTOROLA_PORT_OFFSET 0x10400
+
#define I2O_IRQ_OUTBOUND_POST 0x00000008
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index d698d7709c31..4f1515cae5dc 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -88,6 +88,11 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
struct device *dev = &pdev->dev;
int i;
+ if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+ printk(KERN_ERR "%s: device already claimed\n", c->name);
+ return -ENODEV;
+ }
+
for (i = 0; i < 6; i++) {
/* Skip I/O spaces */
if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
@@ -163,6 +168,24 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
c->in_port = c->base.virt + I2O_IN_PORT;
c->out_port = c->base.virt + I2O_OUT_PORT;
+ /* Motorola/Freescale chip does not follow spec */
+ if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
+ /* Check if CPU is enabled */
+ if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
+ printk(KERN_INFO "%s: MPC82XX needs CPU running to "
+ "service I2O.\n", c->name);
+ i2o_pci_free(c);
+ return -ENODEV;
+ } else {
+ c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
+ c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
+ c->in_port += I2O_MOTOROLA_PORT_OFFSET;
+ c->out_port += I2O_MOTOROLA_PORT_OFFSET;
+ printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
+ c->name);
+ }
+ }
+
if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
@@ -298,7 +321,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
struct i2o_controller *c;
int rc;
struct pci_dev *i960 = NULL;
- int pci_dev_busy = 0;
+ int enabled = pdev->is_enabled;
printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
@@ -308,16 +331,12 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}
- if ((rc = pci_enable_device(pdev))) {
- printk(KERN_WARNING "i2o: couldn't enable device %s\n",
- pci_name(pdev));
- return rc;
- }
-
- if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
- printk(KERN_ERR "i2o: device already claimed\n");
- return -ENODEV;
- }
+ if (!enabled)
+ if ((rc = pci_enable_device(pdev))) {
+ printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+ pci_name(pdev));
+ return rc;
+ }
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
@@ -395,9 +414,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
if ((rc = i2o_pci_alloc(c))) {
printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
- " failed\n", c->name);
- if (rc == -ENODEV)
- pci_dev_busy = 1;
+ "failed\n", c->name);
goto free_controller;
}
@@ -425,7 +442,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
i2o_iop_free(c);
disable:
- if (!pci_dev_busy)
+ if (!enabled)
pci_disable_device(pdev);
return rc;
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
index 701620b6baed..8b3784e2de89 100644
--- a/drivers/mtd/maps/dc21285.c
+++ b/drivers/mtd/maps/dc21285.c
@@ -110,8 +110,9 @@ static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const voi
{
while (len > 0) {
map_word d;
- d.x[0] = *((uint32_t*)from)++;
+ d.x[0] = *((uint32_t*)from);
dc21285_write32(map, d, to);
+ from += 4;
to += 4;
len -= 4;
}
@@ -121,8 +122,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi
{
while (len > 0) {
map_word d;
- d.x[0] = *((uint16_t*)from)++;
+ d.x[0] = *((uint16_t*)from);
dc21285_write16(map, d, to);
+ from += 2;
to += 2;
len -= 2;
}
@@ -131,8 +133,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi
static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
map_word d;
- d.x[0] = *((uint8_t*)from)++;
+ d.x[0] = *((uint8_t*)from);
dc21285_write8(map, d, to);
+ from++;
to++;
len--;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 7488ee7f7caf..7f47124f118d 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -753,9 +753,11 @@ enum tx_desc_status {
enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
struct vortex_extra_stats {
- unsigned long tx_deferred;
- unsigned long tx_multiple_collisions;
- unsigned long rx_bad_ssd;
+ unsigned long tx_deferred;
+ unsigned long tx_max_collisions;
+ unsigned long tx_multiple_collisions;
+ unsigned long tx_single_collisions;
+ unsigned long rx_bad_ssd;
};
struct vortex_private {
@@ -863,12 +865,14 @@ static struct {
const char str[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
{ "tx_deferred" },
+ { "tx_max_collisions" },
{ "tx_multiple_collisions" },
+ { "tx_single_collisions" },
{ "rx_bad_ssd" },
};
/* number of ETHTOOL_GSTATS u64's */
-#define VORTEX_NUM_STATS 3
+#define VORTEX_NUM_STATS 5
static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
int chip_idx, int card_idx);
@@ -2108,9 +2112,12 @@ vortex_error(struct net_device *dev, int status)
iowrite8(0, ioaddr + TxStatus);
if (tx_status & 0x30) { /* txJabber or txUnderrun */
do_tx_reset = 1;
- } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */
- do_tx_reset = 1;
- reset_mask = 0x0108; /* Reset interface logic, but not download logic */
+ } else if (tx_status & 0x08) { /* maxCollisions */
+ vp->xstats.tx_max_collisions++;
+ if (vp->drv_flags & MAX_COLLISION_RESET) {
+ do_tx_reset = 1;
+ reset_mask = 0x0108; /* Reset interface logic, but not download logic */
+ }
} else { /* Merely re-enable the transmitter. */
iowrite16(TxEnable, ioaddr + EL3_CMD);
}
@@ -2926,7 +2933,6 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
EL3WINDOW(6);
vp->stats.tx_carrier_errors += ioread8(ioaddr + 0);
vp->stats.tx_heartbeat_errors += ioread8(ioaddr + 1);
- vp->stats.collisions += ioread8(ioaddr + 3);
vp->stats.tx_window_errors += ioread8(ioaddr + 4);
vp->stats.rx_fifo_errors += ioread8(ioaddr + 5);
vp->stats.tx_packets += ioread8(ioaddr + 6);
@@ -2939,10 +2945,15 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
vp->stats.tx_bytes += ioread16(ioaddr + 12);
/* Extra stats for get_ethtool_stats() */
vp->xstats.tx_multiple_collisions += ioread8(ioaddr + 2);
+ vp->xstats.tx_single_collisions += ioread8(ioaddr + 3);
vp->xstats.tx_deferred += ioread8(ioaddr + 8);
EL3WINDOW(4);
vp->xstats.rx_bad_ssd += ioread8(ioaddr + 12);
+ vp->stats.collisions = vp->xstats.tx_multiple_collisions
+ + vp->xstats.tx_single_collisions
+ + vp->xstats.tx_max_collisions;
+
{
u8 up = ioread8(ioaddr + 13);
vp->stats.rx_bytes += (up & 0x0f) << 16;
@@ -3036,8 +3047,10 @@ static void vortex_get_ethtool_stats(struct net_device *dev,
spin_unlock_irqrestore(&vp->lock, flags);
data[0] = vp->xstats.tx_deferred;
- data[1] = vp->xstats.tx_multiple_collisions;
- data[2] = vp->xstats.rx_bad_ssd;
+ data[1] = vp->xstats.tx_max_collisions;
+ data[2] = vp->xstats.tx_multiple_collisions;
+ data[3] = vp->xstats.tx_single_collisions;
+ data[4] = vp->xstats.rx_bad_ssd;
}
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index f605dea57224..f63c387976cf 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -90,6 +90,15 @@ config PARPORT_ARC
depends on ARM && PARPORT
select PARPORT_NOT_PC
+config PARPORT_IP32
+ tristate "SGI IP32 builtin port (EXPERIMENTAL)"
+ depends on SGI_IP32 && PARPORT && EXPERIMENTAL
+ select PARPORT_NOT_PC
+ help
+ Say Y here if you need support for the parallel port on
+ SGI O2 machines. This code is also available as a module (say M),
+ called parport_ip32. If in doubt, saying N is the safe plan.
+
config PARPORT_AMIGA
tristate "Amiga builtin port"
depends on AMIGA && PARPORT
diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile
index 5372212bb9d9..a19de35f8de2 100644
--- a/drivers/parport/Makefile
+++ b/drivers/parport/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o
obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o
obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o
obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o
+obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 5b887ba5aaf9..690b239ad3a7 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -61,10 +61,10 @@ static void timeout_waiting_on_port (unsigned long cookie)
* set to zero, it returns immediately.
*
* If an interrupt occurs before the timeout period elapses, this
- * function returns one immediately. If it times out, it returns
- * a value greater than zero. An error code less than zero
- * indicates an error (most likely a pending signal), and the
- * calling code should finish what it's doing as soon as it can.
+ * function returns zero immediately. If it times out, it returns
+ * one. An error code less than zero indicates an error (most
+ * likely a pending signal), and the calling code should finish
+ * what it's doing as soon as it can.
*/
int parport_wait_event (struct parport *port, signed long timeout)
@@ -110,7 +110,7 @@ int parport_wait_event (struct parport *port, signed long timeout)
*
* If the status lines take on the desired values before the
* timeout period elapses, parport_poll_peripheral() returns zero
- * immediately. A zero return value greater than zero indicates
+ * immediately. A return value greater than zero indicates
* a timeout. An error code (less than zero) indicates an error,
* most likely a signal that arrived, and the caller should
* finish what it is doing as soon as possible.
diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
new file mode 100644
index 000000000000..46e06e596d73
--- /dev/null
+++ b/drivers/parport/parport_ip32.c
@@ -0,0 +1,2253 @@
+/* Low-level parallel port routines for built-in port on SGI IP32
+ *
+ * Author: Arnaud Giersch <arnaud.giersch@free.fr>
+ *
+ * Based on parport_pc.c by
+ * Phil Blundell, Tim Waugh, Jose Renau, David Campbell,
+ * Andrea Arcangeli, et al.
+ *
+ * Thanks to Ilya A. Volynets-Evenbakh for his help.
+ *
+ * Copyright (C) 2005, 2006 Arnaud Giersch.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Current status:
+ *
+ * Basic SPP and PS2 modes are supported.
+ * Support for parallel port IRQ is present.
+ * Hardware SPP (a.k.a. compatibility), EPP, and ECP modes are
+ * supported.
+ * SPP/ECP FIFO can be driven in PIO or DMA mode. PIO mode can work with
+ * or without interrupt support.
+ *
+ * Hardware ECP mode is not fully implemented (ecp_read_data and
+ * ecp_write_addr are actually missing).
+ *
+ * To do:
+ *
+ * Fully implement ECP mode.
+ * EPP and ECP mode need to be tested. I currently do not own any
+ * peripheral supporting these extended mode, and cannot test them.
+ * If DMA mode works well, decide if support for PIO FIFO modes should be
+ * dropped.
+ * Use the io{read,write} family functions when they become available in
+ * the linux-mips.org tree. Note: the MIPS specific functions readsb()
+ * and writesb() are to be translated by ioread8_rep() and iowrite8_rep()
+ * respectively.
+ */
+
+/* The built-in parallel port on the SGI 02 workstation (a.k.a. IP32) is an
+ * IEEE 1284 parallel port driven by a Texas Instrument TL16PIR552PH chip[1].
+ * This chip supports SPP, bidirectional, EPP and ECP modes. It has a 16 byte
+ * FIFO buffer and supports DMA transfers.
+ *
+ * [1] http://focus.ti.com/docs/prod/folders/print/tl16pir552.html
+ *
+ * Theoretically, we could simply use the parport_pc module. It is however
+ * not so simple. The parport_pc code assumes that the parallel port
+ * registers are port-mapped. On the O2, they are memory-mapped.
+ * Furthermore, each register is replicated on 256 consecutive addresses (as
+ * it is for the built-in serial ports on the same chip).
+ */
+
+/*--- Some configuration defines ---------------------------------------*/
+
+/* DEBUG_PARPORT_IP32
+ * 0 disable debug
+ * 1 standard level: pr_debug1 is enabled
+ * 2 parport_ip32_dump_state is enabled
+ * >=3 verbose level: pr_debug is enabled
+ */
+#if !defined(DEBUG_PARPORT_IP32)
+# define DEBUG_PARPORT_IP32 0 /* 0 (disabled) for production */
+#endif
+
+/*----------------------------------------------------------------------*/
+
+/* Setup DEBUG macros. This is done before any includes, just in case we
+ * activate pr_debug() with DEBUG_PARPORT_IP32 >= 3.
+ */
+#if DEBUG_PARPORT_IP32 == 1
+# warning DEBUG_PARPORT_IP32 == 1
+#elif DEBUG_PARPORT_IP32 == 2
+# warning DEBUG_PARPORT_IP32 == 2
+#elif DEBUG_PARPORT_IP32 >= 3
+# warning DEBUG_PARPORT_IP32 >= 3
+# if !defined(DEBUG)
+# define DEBUG /* enable pr_debug() in kernel.h */
+# endif
+#endif
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/ip32/ip32_ints.h>
+#include <asm/ip32/mace.h>
+
+/*--- Global variables -------------------------------------------------*/
+
+/* Verbose probing on by default for debugging. */
+#if DEBUG_PARPORT_IP32 >= 1
+# define DEFAULT_VERBOSE_PROBING 1
+#else
+# define DEFAULT_VERBOSE_PROBING 0
+#endif
+
+/* Default prefix for printk */
+#define PPIP32 "parport_ip32: "
+
+/*
+ * These are the module parameters:
+ * @features: bit mask of features to enable/disable
+ * (all enabled by default)
+ * @verbose_probing: log chit-chat during initialization
+ */
+#define PARPORT_IP32_ENABLE_IRQ (1U << 0)
+#define PARPORT_IP32_ENABLE_DMA (1U << 1)
+#define PARPORT_IP32_ENABLE_SPP (1U << 2)
+#define PARPORT_IP32_ENABLE_EPP (1U << 3)
+#define PARPORT_IP32_ENABLE_ECP (1U << 4)
+static unsigned int features = ~0U;
+static int verbose_probing = DEFAULT_VERBOSE_PROBING;
+
+/* We do not support more than one port. */
+static struct parport *this_port = NULL;
+
+/* Timing constants for FIFO modes. */
+#define FIFO_NFAULT_TIMEOUT 100 /* milliseconds */
+#define FIFO_POLLING_INTERVAL 50 /* microseconds */
+
+/*--- I/O register definitions -----------------------------------------*/
+
+/**
+ * struct parport_ip32_regs - virtual addresses of parallel port registers
+ * @data: Data Register
+ * @dsr: Device Status Register
+ * @dcr: Device Control Register
+ * @eppAddr: EPP Address Register
+ * @eppData0: EPP Data Register 0
+ * @eppData1: EPP Data Register 1
+ * @eppData2: EPP Data Register 2
+ * @eppData3: EPP Data Register 3
+ * @ecpAFifo: ECP Address FIFO
+ * @fifo: General FIFO register. The same address is used for:
+ * - cFifo, the Parallel Port DATA FIFO
+ * - ecpDFifo, the ECP Data FIFO
+ * - tFifo, the ECP Test FIFO
+ * @cnfgA: Configuration Register A
+ * @cnfgB: Configuration Register B
+ * @ecr: Extended Control Register
+ */
+struct parport_ip32_regs {
+ void __iomem *data;
+ void __iomem *dsr;
+ void __iomem *dcr;
+ void __iomem *eppAddr;
+ void __iomem *eppData0;
+ void __iomem *eppData1;
+ void __iomem *eppData2;
+ void __iomem *eppData3;
+ void __iomem *ecpAFifo;
+ void __iomem *fifo;
+ void __iomem *cnfgA;
+ void __iomem *cnfgB;
+ void __iomem *ecr;
+};
+
+/* Device Status Register */
+#define DSR_nBUSY (1U << 7) /* PARPORT_STATUS_BUSY */
+#define DSR_nACK (1U << 6) /* PARPORT_STATUS_ACK */
+#define DSR_PERROR (1U << 5) /* PARPORT_STATUS_PAPEROUT */
+#define DSR_SELECT (1U << 4) /* PARPORT_STATUS_SELECT */
+#define DSR_nFAULT (1U << 3) /* PARPORT_STATUS_ERROR */
+#define DSR_nPRINT (1U << 2) /* specific to TL16PIR552 */
+/* #define DSR_reserved (1U << 1) */
+#define DSR_TIMEOUT (1U << 0) /* EPP timeout */
+
+/* Device Control Register */
+/* #define DCR_reserved (1U << 7) | (1U << 6) */
+#define DCR_DIR (1U << 5) /* direction */
+#define DCR_IRQ (1U << 4) /* interrupt on nAck */
+#define DCR_SELECT (1U << 3) /* PARPORT_CONTROL_SELECT */
+#define DCR_nINIT (1U << 2) /* PARPORT_CONTROL_INIT */
+#define DCR_AUTOFD (1U << 1) /* PARPORT_CONTROL_AUTOFD */
+#define DCR_STROBE (1U << 0) /* PARPORT_CONTROL_STROBE */
+
+/* ECP Configuration Register A */
+#define CNFGA_IRQ (1U << 7)
+#define CNFGA_ID_MASK ((1U << 6) | (1U << 5) | (1U << 4))
+#define CNFGA_ID_SHIFT 4
+#define CNFGA_ID_16 (00U << CNFGA_ID_SHIFT)
+#define CNFGA_ID_8 (01U << CNFGA_ID_SHIFT)
+#define CNFGA_ID_32 (02U << CNFGA_ID_SHIFT)
+/* #define CNFGA_reserved (1U << 3) */
+#define CNFGA_nBYTEINTRANS (1U << 2)
+#define CNFGA_PWORDLEFT ((1U << 1) | (1U << 0))
+
+/* ECP Configuration Register B */
+#define CNFGB_COMPRESS (1U << 7)
+#define CNFGB_INTRVAL (1U << 6)
+#define CNFGB_IRQ_MASK ((1U << 5) | (1U << 4) | (1U << 3))
+#define CNFGB_IRQ_SHIFT 3
+#define CNFGB_DMA_MASK ((1U << 2) | (1U << 1) | (1U << 0))
+#define CNFGB_DMA_SHIFT 0
+
+/* Extended Control Register */
+#define ECR_MODE_MASK ((1U << 7) | (1U << 6) | (1U << 5))
+#define ECR_MODE_SHIFT 5
+#define ECR_MODE_SPP (00U << ECR_MODE_SHIFT)
+#define ECR_MODE_PS2 (01U << ECR_MODE_SHIFT)
+#define ECR_MODE_PPF (02U << ECR_MODE_SHIFT)
+#define ECR_MODE_ECP (03U << ECR_MODE_SHIFT)
+#define ECR_MODE_EPP (04U << ECR_MODE_SHIFT)
+/* #define ECR_MODE_reserved (05U << ECR_MODE_SHIFT) */
+#define ECR_MODE_TST (06U << ECR_MODE_SHIFT)
+#define ECR_MODE_CFG (07U << ECR_MODE_SHIFT)
+#define ECR_nERRINTR (1U << 4)
+#define ECR_DMAEN (1U << 3)
+#define ECR_SERVINTR (1U << 2)
+#define ECR_F_FULL (1U << 1)
+#define ECR_F_EMPTY (1U << 0)
+
+/*--- Private data -----------------------------------------------------*/
+
+/**
+ * enum parport_ip32_irq_mode - operation mode of interrupt handler
+ * @PARPORT_IP32_IRQ_FWD: forward interrupt to the upper parport layer
+ * @PARPORT_IP32_IRQ_HERE: interrupt is handled locally
+ */
+enum parport_ip32_irq_mode { PARPORT_IP32_IRQ_FWD, PARPORT_IP32_IRQ_HERE };
+
+/**
+ * struct parport_ip32_private - private stuff for &struct parport
+ * @regs: register addresses
+ * @dcr_cache: cached contents of DCR
+ * @dcr_writable: bit mask of writable DCR bits
+ * @pword: number of bytes per PWord
+ * @fifo_depth: number of PWords that FIFO will hold
+ * @readIntrThreshold: minimum number of PWords we can read
+ * if we get an interrupt
+ * @writeIntrThreshold: minimum number of PWords we can write
+ * if we get an interrupt
+ * @irq_mode: operation mode of interrupt handler for this port
+ * @irq_complete: mutex used to wait for an interrupt to occur
+ */
+struct parport_ip32_private {
+ struct parport_ip32_regs regs;
+ unsigned int dcr_cache;
+ unsigned int dcr_writable;
+ unsigned int pword;
+ unsigned int fifo_depth;
+ unsigned int readIntrThreshold;
+ unsigned int writeIntrThreshold;
+ enum parport_ip32_irq_mode irq_mode;
+ struct completion irq_complete;
+};
+
+/*--- Debug code -------------------------------------------------------*/
+
+/*
+ * pr_debug1 - print debug messages
+ *
+ * This is like pr_debug(), but is defined for %DEBUG_PARPORT_IP32 >= 1
+ */
+#if DEBUG_PARPORT_IP32 >= 1
+# define pr_debug1(...) printk(KERN_DEBUG __VA_ARGS__)
+#else /* DEBUG_PARPORT_IP32 < 1 */
+# define pr_debug1(...) do { } while (0)
+#endif
+
+/*
+ * pr_trace, pr_trace1 - trace function calls
+ * @p: pointer to &struct parport
+ * @fmt: printk format string
+ * @...: parameters for format string
+ *
+ * Macros used to trace function calls. The given string is formatted after
+ * function name. pr_trace() uses pr_debug(), and pr_trace1() uses
+ * pr_debug1(). __pr_trace() is the low-level macro and is not to be used
+ * directly.
+ */
+#define __pr_trace(pr, p, fmt, ...) \
+ pr("%s: %s" fmt "\n", \
+ ({ const struct parport *__p = (p); \
+ __p ? __p->name : "parport_ip32"; }), \
+ __func__ , ##__VA_ARGS__)
+#define pr_trace(p, fmt, ...) __pr_trace(pr_debug, p, fmt , ##__VA_ARGS__)
+#define pr_trace1(p, fmt, ...) __pr_trace(pr_debug1, p, fmt , ##__VA_ARGS__)
+
+/*
+ * __pr_probe, pr_probe - print message if @verbose_probing is true
+ * @p: pointer to &struct parport
+ * @fmt: printk format string
+ * @...: parameters for format string
+ *
+ * For new lines, use pr_probe(). Use __pr_probe() for continued lines.
+ */
+#define __pr_probe(...) \
+ do { if (verbose_probing) printk(__VA_ARGS__); } while (0)
+#define pr_probe(p, fmt, ...) \
+ __pr_probe(KERN_INFO PPIP32 "0x%lx: " fmt, (p)->base , ##__VA_ARGS__)
+
+/*
+ * parport_ip32_dump_state - print register status of parport
+ * @p: pointer to &struct parport
+ * @str: string to add in message
+ * @show_ecp_config: shall we dump ECP configuration registers too?
+ *
+ * This function is only here for debugging purpose, and should be used with
+ * care. Reading the parallel port registers may have undesired side effects.
+ * Especially if @show_ecp_config is true, the parallel port is resetted.
+ * This function is only defined if %DEBUG_PARPORT_IP32 >= 2.
+ */
+#if DEBUG_PARPORT_IP32 >= 2
+static void parport_ip32_dump_state(struct parport *p, char *str,
+ unsigned int show_ecp_config)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int i;
+
+ printk(KERN_DEBUG PPIP32 "%s: state (%s):\n", p->name, str);
+ {
+ static const char ecr_modes[8][4] = {"SPP", "PS2", "PPF",
+ "ECP", "EPP", "???",
+ "TST", "CFG"};
+ unsigned int ecr = readb(priv->regs.ecr);
+ printk(KERN_DEBUG PPIP32 " ecr=0x%02x", ecr);
+ printk(" %s",
+ ecr_modes[(ecr & ECR_MODE_MASK) >> ECR_MODE_SHIFT]);
+ if (ecr & ECR_nERRINTR)
+ printk(",nErrIntrEn");
+ if (ecr & ECR_DMAEN)
+ printk(",dmaEn");
+ if (ecr & ECR_SERVINTR)
+ printk(",serviceIntr");
+ if (ecr & ECR_F_FULL)
+ printk(",f_full");
+ if (ecr & ECR_F_EMPTY)
+ printk(",f_empty");
+ printk("\n");
+ }
+ if (show_ecp_config) {
+ unsigned int oecr, cnfgA, cnfgB;
+ oecr = readb(priv->regs.ecr);
+ writeb(ECR_MODE_PS2, priv->regs.ecr);
+ writeb(ECR_MODE_CFG, priv->regs.ecr);
+ cnfgA = readb(priv->regs.cnfgA);
+ cnfgB = readb(priv->regs.cnfgB);
+ writeb(ECR_MODE_PS2, priv->regs.ecr);
+ writeb(oecr, priv->regs.ecr);
+ printk(KERN_DEBUG PPIP32 " cnfgA=0x%02x", cnfgA);
+ printk(" ISA-%s", (cnfgA & CNFGA_IRQ) ? "Level" : "Pulses");
+ switch (cnfgA & CNFGA_ID_MASK) {
+ case CNFGA_ID_8:
+ printk(",8 bits");
+ break;
+ case CNFGA_ID_16:
+ printk(",16 bits");
+ break;
+ case CNFGA_ID_32:
+ printk(",32 bits");
+ break;
+ default:
+ printk(",unknown ID");
+ break;
+ }
+ if (!(cnfgA & CNFGA_nBYTEINTRANS))
+ printk(",ByteInTrans");
+ if ((cnfgA & CNFGA_ID_MASK) != CNFGA_ID_8)
+ printk(",%d byte%s left", cnfgA & CNFGA_PWORDLEFT,
+ ((cnfgA & CNFGA_PWORDLEFT) > 1) ? "s" : "");
+ printk("\n");
+ printk(KERN_DEBUG PPIP32 " cnfgB=0x%02x", cnfgB);
+ printk(" irq=%u,dma=%u",
+ (cnfgB & CNFGB_IRQ_MASK) >> CNFGB_IRQ_SHIFT,
+ (cnfgB & CNFGB_DMA_MASK) >> CNFGB_DMA_SHIFT);
+ printk(",intrValue=%d", !!(cnfgB & CNFGB_INTRVAL));
+ if (cnfgB & CNFGB_COMPRESS)
+ printk(",compress");
+ printk("\n");
+ }
+ for (i = 0; i < 2; i++) {
+ unsigned int dcr = i ? priv->dcr_cache : readb(priv->regs.dcr);
+ printk(KERN_DEBUG PPIP32 " dcr(%s)=0x%02x",
+ i ? "soft" : "hard", dcr);
+ printk(" %s", (dcr & DCR_DIR) ? "rev" : "fwd");
+ if (dcr & DCR_IRQ)
+ printk(",ackIntEn");
+ if (!(dcr & DCR_SELECT))
+ printk(",nSelectIn");
+ if (dcr & DCR_nINIT)
+ printk(",nInit");
+ if (!(dcr & DCR_AUTOFD))
+ printk(",nAutoFD");
+ if (!(dcr & DCR_STROBE))
+ printk(",nStrobe");
+ printk("\n");
+ }
+#define sep (f++ ? ',' : ' ')
+ {
+ unsigned int f = 0;
+ unsigned int dsr = readb(priv->regs.dsr);
+ printk(KERN_DEBUG PPIP32 " dsr=0x%02x", dsr);
+ if (!(dsr & DSR_nBUSY))
+ printk("%cBusy", sep);
+ if (dsr & DSR_nACK)
+ printk("%cnAck", sep);
+ if (dsr & DSR_PERROR)
+ printk("%cPError", sep);
+ if (dsr & DSR_SELECT)
+ printk("%cSelect", sep);
+ if (dsr & DSR_nFAULT)
+ printk("%cnFault", sep);
+ if (!(dsr & DSR_nPRINT))
+ printk("%c(Print)", sep);
+ if (dsr & DSR_TIMEOUT)
+ printk("%cTimeout", sep);
+ printk("\n");
+ }
+#undef sep
+}
+#else /* DEBUG_PARPORT_IP32 < 2 */
+#define parport_ip32_dump_state(...) do { } while (0)
+#endif
+
+/*
+ * CHECK_EXTRA_BITS - track and log extra bits
+ * @p: pointer to &struct parport
+ * @b: byte to inspect
+ * @m: bit mask of authorized bits
+ *
+ * This is used to track and log extra bits that should not be there in
+ * parport_ip32_write_control() and parport_ip32_frob_control(). It is only
+ * defined if %DEBUG_PARPORT_IP32 >= 1.
+ */
+#if DEBUG_PARPORT_IP32 >= 1
+#define CHECK_EXTRA_BITS(p, b, m) \
+ do { \
+ unsigned int __b = (b), __m = (m); \
+ if (__b & ~__m) \
+ pr_debug1(PPIP32 "%s: extra bits in %s(%s): " \
+ "0x%02x/0x%02x\n", \
+ (p)->name, __func__, #b, __b, __m); \
+ } while (0)
+#else /* DEBUG_PARPORT_IP32 < 1 */
+#define CHECK_EXTRA_BITS(...) do { } while (0)
+#endif
+
+/*--- IP32 parallel port DMA operations --------------------------------*/
+
+/**
+ * struct parport_ip32_dma_data - private data needed for DMA operation
+ * @dir: DMA direction (from or to device)
+ * @buf: buffer physical address
+ * @len: buffer length
+ * @next: address of next bytes to DMA transfer
+ * @left: number of bytes remaining
+ * @ctx: next context to write (0: context_a; 1: context_b)
+ * @irq_on: are the DMA IRQs currently enabled?
+ * @lock: spinlock to protect access to the structure
+ */
+struct parport_ip32_dma_data {
+ enum dma_data_direction dir;
+ dma_addr_t buf;
+ dma_addr_t next;
+ size_t len;
+ size_t left;
+ unsigned int ctx;
+ unsigned int irq_on;
+ spinlock_t lock;
+};
+static struct parport_ip32_dma_data parport_ip32_dma;
+
+/**
+ * parport_ip32_dma_setup_context - setup next DMA context
+ * @limit: maximum data size for the context
+ *
+ * The alignment constraints must be verified in caller function, and the
+ * parameter @limit must be set accordingly.
+ */
+static void parport_ip32_dma_setup_context(unsigned int limit)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&parport_ip32_dma.lock, flags);
+ if (parport_ip32_dma.left > 0) {
+ /* Note: ctxreg is "volatile" here only because
+ * mace->perif.ctrl.parport.context_a and context_b are
+ * "volatile". */
+ volatile u64 __iomem *ctxreg = (parport_ip32_dma.ctx == 0) ?
+ &mace->perif.ctrl.parport.context_a :
+ &mace->perif.ctrl.parport.context_b;
+ u64 count;
+ u64 ctxval;
+ if (parport_ip32_dma.left <= limit) {
+ count = parport_ip32_dma.left;
+ ctxval = MACEPAR_CONTEXT_LASTFLAG;
+ } else {
+ count = limit;
+ ctxval = 0;
+ }
+
+ pr_trace(NULL,
+ "(%u): 0x%04x:0x%04x, %u -> %u%s",
+ limit,
+ (unsigned int)parport_ip32_dma.buf,
+ (unsigned int)parport_ip32_dma.next,
+ (unsigned int)count,
+ parport_ip32_dma.ctx, ctxval ? "*" : "");
+
+ ctxval |= parport_ip32_dma.next &
+ MACEPAR_CONTEXT_BASEADDR_MASK;
+ ctxval |= ((count - 1) << MACEPAR_CONTEXT_DATALEN_SHIFT) &
+ MACEPAR_CONTEXT_DATALEN_MASK;
+ writeq(ctxval, ctxreg);
+ parport_ip32_dma.next += count;
+ parport_ip32_dma.left -= count;
+ parport_ip32_dma.ctx ^= 1U;
+ }
+ /* If there is nothing more to send, disable IRQs to avoid to
+ * face an IRQ storm which can lock the machine. Disable them
+ * only once. */
+ if (parport_ip32_dma.left == 0 && parport_ip32_dma.irq_on) {
+ pr_debug(PPIP32 "IRQ off (ctx)\n");
+ disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
+ disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 0;
+ }
+ spin_unlock_irqrestore(&parport_ip32_dma.lock, flags);
+}
+
+/**
+ * parport_ip32_dma_interrupt - DMA interrupt handler
+ * @irq: interrupt number
+ * @dev_id: unused
+ * @regs: pointer to &struct pt_regs
+ */
+static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ if (parport_ip32_dma.left)
+ pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx);
+ parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
+ return IRQ_HANDLED;
+}
+
+#if DEBUG_PARPORT_IP32
+static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ pr_trace1(NULL, "(%d)", irq);
+ return IRQ_HANDLED;
+}
+#endif
+
+/**
+ * parport_ip32_dma_start - begins a DMA transfer
+ * @dir: DMA direction: DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @addr: pointer to data buffer
+ * @count: buffer size
+ *
+ * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
+ * correctly balanced.
+ */
+static int parport_ip32_dma_start(enum dma_data_direction dir,
+ void *addr, size_t count)
+{
+ unsigned int limit;
+ u64 ctrl;
+
+ pr_trace(NULL, "(%d, %lu)", dir, (unsigned long)count);
+
+ /* FIXME - add support for DMA_FROM_DEVICE. In this case, buffer must
+ * be 64 bytes aligned. */
+ BUG_ON(dir != DMA_TO_DEVICE);
+
+ /* Reset DMA controller */
+ ctrl = MACEPAR_CTLSTAT_RESET;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+ /* DMA IRQs should normally be enabled */
+ if (!parport_ip32_dma.irq_on) {
+ WARN_ON(1);
+ enable_irq(MACEISA_PAR_CTXA_IRQ);
+ enable_irq(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 1;
+ }
+
+ /* Prepare DMA pointers */
+ parport_ip32_dma.dir = dir;
+ parport_ip32_dma.buf = dma_map_single(NULL, addr, count, dir);
+ parport_ip32_dma.len = count;
+ parport_ip32_dma.next = parport_ip32_dma.buf;
+ parport_ip32_dma.left = parport_ip32_dma.len;
+ parport_ip32_dma.ctx = 0;
+
+ /* Setup DMA direction and first two contexts */
+ ctrl = (dir == DMA_TO_DEVICE) ? 0 : MACEPAR_CTLSTAT_DIRECTION;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+ /* Single transfer should not cross a 4K page boundary */
+ limit = MACEPAR_CONTEXT_DATA_BOUND -
+ (parport_ip32_dma.next & (MACEPAR_CONTEXT_DATA_BOUND - 1));
+ parport_ip32_dma_setup_context(limit);
+ parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
+
+ /* Real start of DMA transfer */
+ ctrl |= MACEPAR_CTLSTAT_ENABLE;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+ return 0;
+}
+
+/**
+ * parport_ip32_dma_stop - ends a running DMA transfer
+ *
+ * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
+ * correctly balanced.
+ */
+static void parport_ip32_dma_stop(void)
+{
+ u64 ctx_a;
+ u64 ctx_b;
+ u64 ctrl;
+ u64 diag;
+ size_t res[2]; /* {[0] = res_a, [1] = res_b} */
+
+ pr_trace(NULL, "()");
+
+ /* Disable IRQs */
+ spin_lock_irq(&parport_ip32_dma.lock);
+ if (parport_ip32_dma.irq_on) {
+ pr_debug(PPIP32 "IRQ off (stop)\n");
+ disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
+ disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 0;
+ }
+ spin_unlock_irq(&parport_ip32_dma.lock);
+ /* Force IRQ synchronization, even if the IRQs were disabled
+ * elsewhere. */
+ synchronize_irq(MACEISA_PAR_CTXA_IRQ);
+ synchronize_irq(MACEISA_PAR_CTXB_IRQ);
+
+ /* Stop DMA transfer */
+ ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
+ ctrl &= ~MACEPAR_CTLSTAT_ENABLE;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+ /* Adjust residue (parport_ip32_dma.left) */
+ ctx_a = readq(&mace->perif.ctrl.parport.context_a);
+ ctx_b = readq(&mace->perif.ctrl.parport.context_b);
+ ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
+ diag = readq(&mace->perif.ctrl.parport.diagnostic);
+ res[0] = (ctrl & MACEPAR_CTLSTAT_CTXA_VALID) ?
+ 1 + ((ctx_a & MACEPAR_CONTEXT_DATALEN_MASK) >>
+ MACEPAR_CONTEXT_DATALEN_SHIFT) :
+ 0;
+ res[1] = (ctrl & MACEPAR_CTLSTAT_CTXB_VALID) ?
+ 1 + ((ctx_b & MACEPAR_CONTEXT_DATALEN_MASK) >>
+ MACEPAR_CONTEXT_DATALEN_SHIFT) :
+ 0;
+ if (diag & MACEPAR_DIAG_DMACTIVE)
+ res[(diag & MACEPAR_DIAG_CTXINUSE) != 0] =
+ 1 + ((diag & MACEPAR_DIAG_CTRMASK) >>
+ MACEPAR_DIAG_CTRSHIFT);
+ parport_ip32_dma.left += res[0] + res[1];
+
+ /* Reset DMA controller, and re-enable IRQs */
+ ctrl = MACEPAR_CTLSTAT_RESET;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+ pr_debug(PPIP32 "IRQ on (stop)\n");
+ enable_irq(MACEISA_PAR_CTXA_IRQ);
+ enable_irq(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 1;
+
+ dma_unmap_single(NULL, parport_ip32_dma.buf, parport_ip32_dma.len,
+ parport_ip32_dma.dir);
+}
+
+/**
+ * parport_ip32_dma_get_residue - get residue from last DMA transfer
+ *
+ * Returns the number of bytes remaining from last DMA transfer.
+ */
+static inline size_t parport_ip32_dma_get_residue(void)
+{
+ return parport_ip32_dma.left;
+}
+
+/**
+ * parport_ip32_dma_register - initialize DMA engine
+ *
+ * Returns zero for success.
+ */
+static int parport_ip32_dma_register(void)
+{
+ int err;
+
+ spin_lock_init(&parport_ip32_dma.lock);
+ parport_ip32_dma.irq_on = 1;
+
+ /* Reset DMA controller */
+ writeq(MACEPAR_CTLSTAT_RESET, &mace->perif.ctrl.parport.cntlstat);
+
+ /* Request IRQs */
+ err = request_irq(MACEISA_PAR_CTXA_IRQ, parport_ip32_dma_interrupt,
+ 0, "parport_ip32", NULL);
+ if (err)
+ goto fail_a;
+ err = request_irq(MACEISA_PAR_CTXB_IRQ, parport_ip32_dma_interrupt,
+ 0, "parport_ip32", NULL);
+ if (err)
+ goto fail_b;
+#if DEBUG_PARPORT_IP32
+ /* FIXME - what is this IRQ for? */
+ err = request_irq(MACEISA_PAR_MERR_IRQ, parport_ip32_merr_interrupt,
+ 0, "parport_ip32", NULL);
+ if (err)
+ goto fail_merr;
+#endif
+ return 0;
+
+#if DEBUG_PARPORT_IP32
+fail_merr:
+ free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
+#endif
+fail_b:
+ free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
+fail_a:
+ return err;
+}
+
+/**
+ * parport_ip32_dma_unregister - release and free resources for DMA engine
+ */
+static void parport_ip32_dma_unregister(void)
+{
+#if DEBUG_PARPORT_IP32
+ free_irq(MACEISA_PAR_MERR_IRQ, NULL);
+#endif
+ free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
+ free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
+}
+
+/*--- Interrupt handlers and associates --------------------------------*/
+
+/**
+ * parport_ip32_wakeup - wakes up code waiting for an interrupt
+ * @p: pointer to &struct parport
+ */
+static inline void parport_ip32_wakeup(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ complete(&priv->irq_complete);
+}
+
+/**
+ * parport_ip32_interrupt - interrupt handler
+ * @irq: interrupt number
+ * @dev_id: pointer to &struct parport
+ * @regs: pointer to &struct pt_regs
+ *
+ * Caught interrupts are forwarded to the upper parport layer if IRQ_mode is
+ * %PARPORT_IP32_IRQ_FWD.
+ */
+static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct parport * const p = dev_id;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ enum parport_ip32_irq_mode irq_mode = priv->irq_mode;
+ switch (irq_mode) {
+ case PARPORT_IP32_IRQ_FWD:
+ parport_generic_irq(irq, p, regs);
+ break;
+ case PARPORT_IP32_IRQ_HERE:
+ parport_ip32_wakeup(p);
+ break;
+ }
+ return IRQ_HANDLED;
+}
+
+/*--- Some utility function to manipulate ECR register -----------------*/
+
+/**
+ * parport_ip32_read_econtrol - read contents of the ECR register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned int parport_ip32_read_econtrol(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return readb(priv->regs.ecr);
+}
+
+/**
+ * parport_ip32_write_econtrol - write new contents to the ECR register
+ * @p: pointer to &struct parport
+ * @c: new value to write
+ */
+static inline void parport_ip32_write_econtrol(struct parport *p,
+ unsigned int c)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ writeb(c, priv->regs.ecr);
+}
+
+/**
+ * parport_ip32_frob_econtrol - change bits from the ECR register
+ * @p: pointer to &struct parport
+ * @mask: bit mask of bits to change
+ * @val: new value for changed bits
+ *
+ * Read from the ECR, mask out the bits in @mask, exclusive-or with the bits
+ * in @val, and write the result to the ECR.
+ */
+static inline void parport_ip32_frob_econtrol(struct parport *p,
+ unsigned int mask,
+ unsigned int val)
+{
+ unsigned int c;
+ c = (parport_ip32_read_econtrol(p) & ~mask) ^ val;
+ parport_ip32_write_econtrol(p, c);
+}
+
+/**
+ * parport_ip32_set_mode - change mode of ECP port
+ * @p: pointer to &struct parport
+ * @mode: new mode to write in ECR
+ *
+ * ECR is reset in a sane state (interrupts and DMA disabled), and placed in
+ * mode @mode. Go through PS2 mode if needed.
+ */
+static void parport_ip32_set_mode(struct parport *p, unsigned int mode)
+{
+ unsigned int omode;
+
+ mode &= ECR_MODE_MASK;
+ omode = parport_ip32_read_econtrol(p) & ECR_MODE_MASK;
+
+ if (!(mode == ECR_MODE_SPP || mode == ECR_MODE_PS2
+ || omode == ECR_MODE_SPP || omode == ECR_MODE_PS2)) {
+ /* We have to go through PS2 mode */
+ unsigned int ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+ parport_ip32_write_econtrol(p, ecr);
+ }
+ parport_ip32_write_econtrol(p, mode | ECR_nERRINTR | ECR_SERVINTR);
+}
+
+/*--- Basic functions needed for parport -------------------------------*/
+
+/**
+ * parport_ip32_read_data - return current contents of the DATA register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned char parport_ip32_read_data(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return readb(priv->regs.data);
+}
+
+/**
+ * parport_ip32_write_data - set new contents for the DATA register
+ * @p: pointer to &struct parport
+ * @d: new value to write
+ */
+static inline void parport_ip32_write_data(struct parport *p, unsigned char d)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ writeb(d, priv->regs.data);
+}
+
+/**
+ * parport_ip32_read_status - return current contents of the DSR register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned char parport_ip32_read_status(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return readb(priv->regs.dsr);
+}
+
+/**
+ * __parport_ip32_read_control - return cached contents of the DCR register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned int __parport_ip32_read_control(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return priv->dcr_cache; /* use soft copy */
+}
+
+/**
+ * __parport_ip32_write_control - set new contents for the DCR register
+ * @p: pointer to &struct parport
+ * @c: new value to write
+ */
+static inline void __parport_ip32_write_control(struct parport *p,
+ unsigned int c)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ CHECK_EXTRA_BITS(p, c, priv->dcr_writable);
+ c &= priv->dcr_writable; /* only writable bits */
+ writeb(c, priv->regs.dcr);
+ priv->dcr_cache = c; /* update soft copy */
+}
+
+/**
+ * __parport_ip32_frob_control - change bits from the DCR register
+ * @p: pointer to &struct parport
+ * @mask: bit mask of bits to change
+ * @val: new value for changed bits
+ *
+ * This is equivalent to read from the DCR, mask out the bits in @mask,
+ * exclusive-or with the bits in @val, and write the result to the DCR.
+ * Actually, the cached contents of the DCR is used.
+ */
+static inline void __parport_ip32_frob_control(struct parport *p,
+ unsigned int mask,
+ unsigned int val)
+{
+ unsigned int c;
+ c = (__parport_ip32_read_control(p) & ~mask) ^ val;
+ __parport_ip32_write_control(p, c);
+}
+
+/**
+ * parport_ip32_read_control - return cached contents of the DCR register
+ * @p: pointer to &struct parport
+ *
+ * The return value is masked so as to only return the value of %DCR_STROBE,
+ * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline unsigned char parport_ip32_read_control(struct parport *p)
+{
+ const unsigned int rm =
+ DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+ return __parport_ip32_read_control(p) & rm;
+}
+
+/**
+ * parport_ip32_write_control - set new contents for the DCR register
+ * @p: pointer to &struct parport
+ * @c: new value to write
+ *
+ * The value is masked so as to only change the value of %DCR_STROBE,
+ * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline void parport_ip32_write_control(struct parport *p,
+ unsigned char c)
+{
+ const unsigned int wm =
+ DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+ CHECK_EXTRA_BITS(p, c, wm);
+ __parport_ip32_frob_control(p, wm, c & wm);
+}
+
+/**
+ * parport_ip32_frob_control - change bits from the DCR register
+ * @p: pointer to &struct parport
+ * @mask: bit mask of bits to change
+ * @val: new value for changed bits
+ *
+ * This differs from __parport_ip32_frob_control() in that it only allows to
+ * change the value of %DCR_STROBE, %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline unsigned char parport_ip32_frob_control(struct parport *p,
+ unsigned char mask,
+ unsigned char val)
+{
+ const unsigned int wm =
+ DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+ CHECK_EXTRA_BITS(p, mask, wm);
+ CHECK_EXTRA_BITS(p, val, wm);
+ __parport_ip32_frob_control(p, mask & wm, val & wm);
+ return parport_ip32_read_control(p);
+}
+
+/**
+ * parport_ip32_disable_irq - disable interrupts on the rising edge of nACK
+ * @p: pointer to &struct parport
+ */
+static inline void parport_ip32_disable_irq(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_IRQ, 0);
+}
+
+/**
+ * parport_ip32_enable_irq - enable interrupts on the rising edge of nACK
+ * @p: pointer to &struct parport
+ */
+static inline void parport_ip32_enable_irq(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_IRQ, DCR_IRQ);
+}
+
+/**
+ * parport_ip32_data_forward - enable host-to-peripheral communications
+ * @p: pointer to &struct parport
+ *
+ * Enable the data line drivers, for 8-bit host-to-peripheral communications.
+ */
+static inline void parport_ip32_data_forward(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_DIR, 0);
+}
+
+/**
+ * parport_ip32_data_reverse - enable peripheral-to-host communications
+ * @p: pointer to &struct parport
+ *
+ * Place the data bus in a high impedance state, if @p->modes has the
+ * PARPORT_MODE_TRISTATE bit set.
+ */
+static inline void parport_ip32_data_reverse(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_DIR, DCR_DIR);
+}
+
+/**
+ * parport_ip32_init_state - for core parport code
+ * @dev: pointer to &struct pardevice
+ * @s: pointer to &struct parport_state to initialize
+ */
+static void parport_ip32_init_state(struct pardevice *dev,
+ struct parport_state *s)
+{
+ s->u.ip32.dcr = DCR_SELECT | DCR_nINIT;
+ s->u.ip32.ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+}
+
+/**
+ * parport_ip32_save_state - for core parport code
+ * @p: pointer to &struct parport
+ * @s: pointer to &struct parport_state to save state to
+ */
+static void parport_ip32_save_state(struct parport *p,
+ struct parport_state *s)
+{
+ s->u.ip32.dcr = __parport_ip32_read_control(p);
+ s->u.ip32.ecr = parport_ip32_read_econtrol(p);
+}
+
+/**
+ * parport_ip32_restore_state - for core parport code
+ * @p: pointer to &struct parport
+ * @s: pointer to &struct parport_state to restore state from
+ */
+static void parport_ip32_restore_state(struct parport *p,
+ struct parport_state *s)
+{
+ parport_ip32_set_mode(p, s->u.ip32.ecr & ECR_MODE_MASK);
+ parport_ip32_write_econtrol(p, s->u.ip32.ecr);
+ __parport_ip32_write_control(p, s->u.ip32.dcr);
+}
+
+/*--- EPP mode functions -----------------------------------------------*/
+
+/**
+ * parport_ip32_clear_epp_timeout - clear Timeout bit in EPP mode
+ * @p: pointer to &struct parport
+ *
+ * Returns 1 if the Timeout bit is clear, and 0 otherwise.
+ */
+static unsigned int parport_ip32_clear_epp_timeout(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int cleared;
+
+ if (!(parport_ip32_read_status(p) & DSR_TIMEOUT))
+ cleared = 1;
+ else {
+ unsigned int r;
+ /* To clear timeout some chips require double read */
+ parport_ip32_read_status(p);
+ r = parport_ip32_read_status(p);
+ /* Some reset by writing 1 */
+ writeb(r | DSR_TIMEOUT, priv->regs.dsr);
+ /* Others by writing 0 */
+ writeb(r & ~DSR_TIMEOUT, priv->regs.dsr);
+
+ r = parport_ip32_read_status(p);
+ cleared = !(r & DSR_TIMEOUT);
+ }
+
+ pr_trace(p, "(): %s", cleared ? "cleared" : "failed");
+ return cleared;
+}
+
+/**
+ * parport_ip32_epp_read - generic EPP read function
+ * @eppreg: I/O register to read from
+ * @p: pointer to &struct parport
+ * @buf: buffer to store read data
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read(void __iomem *eppreg,
+ struct parport *p, void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ size_t got;
+ parport_ip32_set_mode(p, ECR_MODE_EPP);
+ parport_ip32_data_reverse(p);
+ parport_ip32_write_control(p, DCR_nINIT);
+ if ((flags & PARPORT_EPP_FAST) && (len > 1)) {
+ readsb(eppreg, buf, len);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ return -EIO;
+ }
+ got = len;
+ } else {
+ u8 *bufp = buf;
+ for (got = 0; got < len; got++) {
+ *bufp++ = readb(eppreg);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ break;
+ }
+ }
+ }
+ parport_ip32_data_forward(p);
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ return got;
+}
+
+/**
+ * parport_ip32_epp_write - generic EPP write function
+ * @eppreg: I/O register to write to
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write(void __iomem *eppreg,
+ struct parport *p, const void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ size_t written;
+ parport_ip32_set_mode(p, ECR_MODE_EPP);
+ parport_ip32_data_forward(p);
+ parport_ip32_write_control(p, DCR_nINIT);
+ if ((flags & PARPORT_EPP_FAST) && (len > 1)) {
+ writesb(eppreg, buf, len);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ return -EIO;
+ }
+ written = len;
+ } else {
+ const u8 *bufp = buf;
+ for (written = 0; written < len; written++) {
+ writeb(*bufp++, eppreg);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ break;
+ }
+ }
+ }
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ return written;
+}
+
+/**
+ * parport_ip32_epp_read_data - read a block of data in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer to store read data
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read_data(struct parport *p, void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_read(priv->regs.eppData0, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_write_data - write a block of data in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write_data(struct parport *p, const void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_write(priv->regs.eppData0, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_read_addr - read a block of addresses in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer to store read data
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read_addr(struct parport *p, void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_read(priv->regs.eppAddr, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_write_addr - write a block of addresses in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write_addr(struct parport *p, const void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_write(priv->regs.eppAddr, p, buf, len, flags);
+}
+
+/*--- ECP mode functions (FIFO) ----------------------------------------*/
+
+/**
+ * parport_ip32_fifo_wait_break - check if the waiting function should return
+ * @p: pointer to &struct parport
+ * @expire: timeout expiring date, in jiffies
+ *
+ * parport_ip32_fifo_wait_break() checks if the waiting function should return
+ * immediately or not. The break conditions are:
+ * - expired timeout;
+ * - a pending signal;
+ * - nFault asserted low.
+ * This function also calls cond_resched().
+ */
+static unsigned int parport_ip32_fifo_wait_break(struct parport *p,
+ unsigned long expire)
+{
+ cond_resched();
+ if (time_after(jiffies, expire)) {
+ pr_debug1(PPIP32 "%s: FIFO write timed out\n", p->name);
+ return 1;
+ }
+ if (signal_pending(current)) {
+ pr_debug1(PPIP32 "%s: Signal pending\n", p->name);
+ return 1;
+ }
+ if (!(parport_ip32_read_status(p) & DSR_nFAULT)) {
+ pr_debug1(PPIP32 "%s: nFault asserted low\n", p->name);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * parport_ip32_fwp_wait_polling - wait for FIFO to empty (polling)
+ * @p: pointer to &struct parport
+ *
+ * Returns the number of bytes that can safely be written in the FIFO. A
+ * return value of zero means that the calling function should terminate as
+ * fast as possible.
+ */
+static unsigned int parport_ip32_fwp_wait_polling(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ unsigned long expire;
+ unsigned int count;
+ unsigned int ecr;
+
+ expire = jiffies + physport->cad->timeout;
+ count = 0;
+ while (1) {
+ if (parport_ip32_fifo_wait_break(p, expire))
+ break;
+
+ /* Check FIFO state. We do nothing when the FIFO is nor full,
+ * nor empty. It appears that the FIFO full bit is not always
+ * reliable, the FIFO state is sometimes wrongly reported, and
+ * the chip gets confused if we give it another byte. */
+ ecr = parport_ip32_read_econtrol(p);
+ if (ecr & ECR_F_EMPTY) {
+ /* FIFO is empty, fill it up */
+ count = priv->fifo_depth;
+ break;
+ }
+
+ /* Wait a moment... */
+ udelay(FIFO_POLLING_INTERVAL);
+ } /* while (1) */
+
+ return count;
+}
+
+/**
+ * parport_ip32_fwp_wait_interrupt - wait for FIFO to empty (interrupt-driven)
+ * @p: pointer to &struct parport
+ *
+ * Returns the number of bytes that can safely be written in the FIFO. A
+ * return value of zero means that the calling function should terminate as
+ * fast as possible.
+ */
+static unsigned int parport_ip32_fwp_wait_interrupt(struct parport *p)
+{
+ static unsigned int lost_interrupt = 0;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ unsigned long nfault_timeout;
+ unsigned long expire;
+ unsigned int count;
+ unsigned int ecr;
+
+ nfault_timeout = min((unsigned long)physport->cad->timeout,
+ msecs_to_jiffies(FIFO_NFAULT_TIMEOUT));
+ expire = jiffies + physport->cad->timeout;
+ count = 0;
+ while (1) {
+ if (parport_ip32_fifo_wait_break(p, expire))
+ break;
+
+ /* Initialize mutex used to take interrupts into account */
+ INIT_COMPLETION(priv->irq_complete);
+
+ /* Enable serviceIntr */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+ /* Enabling serviceIntr while the FIFO is empty does not
+ * always generate an interrupt, so check for emptiness
+ * now. */
+ ecr = parport_ip32_read_econtrol(p);
+ if (!(ecr & ECR_F_EMPTY)) {
+ /* FIFO is not empty: wait for an interrupt or a
+ * timeout to occur */
+ wait_for_completion_interruptible_timeout(
+ &priv->irq_complete, nfault_timeout);
+ ecr = parport_ip32_read_econtrol(p);
+ if ((ecr & ECR_F_EMPTY) && !(ecr & ECR_SERVINTR)
+ && !lost_interrupt) {
+ printk(KERN_WARNING PPIP32
+ "%s: lost interrupt in %s\n",
+ p->name, __func__);
+ lost_interrupt = 1;
+ }
+ }
+
+ /* Disable serviceIntr */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, ECR_SERVINTR);
+
+ /* Check FIFO state */
+ if (ecr & ECR_F_EMPTY) {
+ /* FIFO is empty, fill it up */
+ count = priv->fifo_depth;
+ break;
+ } else if (ecr & ECR_SERVINTR) {
+ /* FIFO is not empty, but we know that can safely push
+ * writeIntrThreshold bytes into it */
+ count = priv->writeIntrThreshold;
+ break;
+ }
+ /* FIFO is not empty, and we did not get any interrupt.
+ * Either it's time to check for nFault, or a signal is
+ * pending. This is verified in
+ * parport_ip32_fifo_wait_break(), so we continue the loop. */
+ } /* while (1) */
+
+ return count;
+}
+
+/**
+ * parport_ip32_fifo_write_block_pio - write a block of data (PIO mode)
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ *
+ * Uses PIO to write the contents of the buffer @buf into the parallel port
+ * FIFO. Returns the number of bytes that were actually written. It can work
+ * with or without the help of interrupts. The parallel port must be
+ * correctly initialized before calling parport_ip32_fifo_write_block_pio().
+ */
+static size_t parport_ip32_fifo_write_block_pio(struct parport *p,
+ const void *buf, size_t len)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ const u8 *bufp = buf;
+ size_t left = len;
+
+ priv->irq_mode = PARPORT_IP32_IRQ_HERE;
+
+ while (left > 0) {
+ unsigned int count;
+
+ count = (p->irq == PARPORT_IRQ_NONE) ?
+ parport_ip32_fwp_wait_polling(p) :
+ parport_ip32_fwp_wait_interrupt(p);
+ if (count == 0)
+ break; /* Transmission should be stopped */
+ if (count > left)
+ count = left;
+ if (count == 1) {
+ writeb(*bufp, priv->regs.fifo);
+ bufp++, left--;
+ } else {
+ writesb(priv->regs.fifo, bufp, count);
+ bufp += count, left -= count;
+ }
+ }
+
+ priv->irq_mode = PARPORT_IP32_IRQ_FWD;
+
+ return len - left;
+}
+
+/**
+ * parport_ip32_fifo_write_block_dma - write a block of data (DMA mode)
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ *
+ * Uses DMA to write the contents of the buffer @buf into the parallel port
+ * FIFO. Returns the number of bytes that were actually written. The
+ * parallel port must be correctly initialized before calling
+ * parport_ip32_fifo_write_block_dma().
+ */
+static size_t parport_ip32_fifo_write_block_dma(struct parport *p,
+ const void *buf, size_t len)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ unsigned long nfault_timeout;
+ unsigned long expire;
+ size_t written;
+ unsigned int ecr;
+
+ priv->irq_mode = PARPORT_IP32_IRQ_HERE;
+
+ parport_ip32_dma_start(DMA_TO_DEVICE, (void *)buf, len);
+ INIT_COMPLETION(priv->irq_complete);
+ parport_ip32_frob_econtrol(p, ECR_DMAEN | ECR_SERVINTR, ECR_DMAEN);
+
+ nfault_timeout = min((unsigned long)physport->cad->timeout,
+ msecs_to_jiffies(FIFO_NFAULT_TIMEOUT));
+ expire = jiffies + physport->cad->timeout;
+ while (1) {
+ if (parport_ip32_fifo_wait_break(p, expire))
+ break;
+ wait_for_completion_interruptible_timeout(&priv->irq_complete,
+ nfault_timeout);
+ ecr = parport_ip32_read_econtrol(p);
+ if (ecr & ECR_SERVINTR)
+ break; /* DMA transfer just finished */
+ }
+ parport_ip32_dma_stop();
+ written = len - parport_ip32_dma_get_residue();
+
+ priv->irq_mode = PARPORT_IP32_IRQ_FWD;
+
+ return written;
+}
+
+/**
+ * parport_ip32_fifo_write_block - write a block of data
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ *
+ * Uses PIO or DMA to write the contents of the buffer @buf into the parallel
+ * p FIFO. Returns the number of bytes that were actually written.
+ */
+static size_t parport_ip32_fifo_write_block(struct parport *p,
+ const void *buf, size_t len)
+{
+ size_t written = 0;
+ if (len)
+ /* FIXME - Maybe some threshold value should be set for @len
+ * under which we revert to PIO mode? */
+ written = (p->modes & PARPORT_MODE_DMA) ?
+ parport_ip32_fifo_write_block_dma(p, buf, len) :
+ parport_ip32_fifo_write_block_pio(p, buf, len);
+ return written;
+}
+
+/**
+ * parport_ip32_drain_fifo - wait for FIFO to empty
+ * @p: pointer to &struct parport
+ * @timeout: timeout, in jiffies
+ *
+ * This function waits for FIFO to empty. It returns 1 when FIFO is empty, or
+ * 0 if the timeout @timeout is reached before, or if a signal is pending.
+ */
+static unsigned int parport_ip32_drain_fifo(struct parport *p,
+ unsigned long timeout)
+{
+ unsigned long expire = jiffies + timeout;
+ unsigned int polling_interval;
+ unsigned int counter;
+
+ /* Busy wait for approx. 200us */
+ for (counter = 0; counter < 40; counter++) {
+ if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY)
+ break;
+ if (time_after(jiffies, expire))
+ break;
+ if (signal_pending(current))
+ break;
+ udelay(5);
+ }
+ /* Poll slowly. Polling interval starts with 1 millisecond, and is
+ * increased exponentially until 128. */
+ polling_interval = 1; /* msecs */
+ while (!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY)) {
+ if (time_after_eq(jiffies, expire))
+ break;
+ msleep_interruptible(polling_interval);
+ if (signal_pending(current))
+ break;
+ if (polling_interval < 128)
+ polling_interval *= 2;
+ }
+
+ return !!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY);
+}
+
+/**
+ * parport_ip32_get_fifo_residue - reset FIFO
+ * @p: pointer to &struct parport
+ * @mode: current operation mode (ECR_MODE_PPF or ECR_MODE_ECP)
+ *
+ * This function resets FIFO, and returns the number of bytes remaining in it.
+ */
+static unsigned int parport_ip32_get_fifo_residue(struct parport *p,
+ unsigned int mode)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int residue;
+ unsigned int cnfga;
+
+ /* FIXME - We are missing one byte if the printer is off-line. I
+ * don't know how to detect this. It looks that the full bit is not
+ * always reliable. For the moment, the problem is avoided in most
+ * cases by testing for BUSY in parport_ip32_compat_write_data().
+ */
+ if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY)
+ residue = 0;
+ else {
+ pr_debug1(PPIP32 "%s: FIFO is stuck\n", p->name);
+
+ /* Stop all transfers.
+ *
+ * Microsoft's document instructs to drive DCR_STROBE to 0,
+ * but it doesn't work (at least in Compatibility mode, not
+ * tested in ECP mode). Switching directly to Test mode (as
+ * in parport_pc) is not an option: it does confuse the port,
+ * ECP service interrupts are no more working after that. A
+ * hard reset is then needed to revert to a sane state.
+ *
+ * Let's hope that the FIFO is really stuck and that the
+ * peripheral doesn't wake up now.
+ */
+ parport_ip32_frob_control(p, DCR_STROBE, 0);
+
+ /* Fill up FIFO */
+ for (residue = priv->fifo_depth; residue > 0; residue--) {
+ if (parport_ip32_read_econtrol(p) & ECR_F_FULL)
+ break;
+ writeb(0x00, priv->regs.fifo);
+ }
+ }
+ if (residue)
+ pr_debug1(PPIP32 "%s: %d PWord%s left in FIFO\n",
+ p->name, residue,
+ (residue == 1) ? " was" : "s were");
+
+ /* Now reset the FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+
+ /* Host recovery for ECP mode */
+ if (mode == ECR_MODE_ECP) {
+ parport_ip32_data_reverse(p);
+ parport_ip32_frob_control(p, DCR_nINIT, 0);
+ if (parport_wait_peripheral(p, DSR_PERROR, 0))
+ pr_debug1(PPIP32 "%s: PEerror timeout 1 in %s\n",
+ p->name, __func__);
+ parport_ip32_frob_control(p, DCR_STROBE, DCR_STROBE);
+ parport_ip32_frob_control(p, DCR_nINIT, DCR_nINIT);
+ if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR))
+ pr_debug1(PPIP32 "%s: PEerror timeout 2 in %s\n",
+ p->name, __func__);
+ }
+
+ /* Adjust residue if needed */
+ parport_ip32_set_mode(p, ECR_MODE_CFG);
+ cnfga = readb(priv->regs.cnfgA);
+ if (!(cnfga & CNFGA_nBYTEINTRANS)) {
+ pr_debug1(PPIP32 "%s: cnfgA contains 0x%02x\n",
+ p->name, cnfga);
+ pr_debug1(PPIP32 "%s: Accounting for extra byte\n",
+ p->name);
+ residue++;
+ }
+
+ /* Don't care about partial PWords since we do not support
+ * PWord != 1 byte. */
+
+ /* Back to forward PS2 mode. */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_data_forward(p);
+
+ return residue;
+}
+
+/**
+ * parport_ip32_compat_write_data - write a block of data in SPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: ignored
+ */
+static size_t parport_ip32_compat_write_data(struct parport *p,
+ const void *buf, size_t len,
+ int flags)
+{
+ static unsigned int ready_before = 1;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ size_t written = 0;
+
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
+ return parport_ieee1284_write_compat(p, buf, len, flags);
+
+ /* Reset FIFO, go in forward mode, and disable ackIntEn */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ parport_ip32_data_forward(p);
+ parport_ip32_disable_irq(p);
+ parport_ip32_set_mode(p, ECR_MODE_PPF);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* Wait for peripheral to become ready */
+ if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,
+ DSR_nBUSY | DSR_nFAULT)) {
+ /* Avoid to flood the logs */
+ if (ready_before)
+ printk(KERN_INFO PPIP32 "%s: not ready in %s\n",
+ p->name, __func__);
+ ready_before = 0;
+ goto stop;
+ }
+ ready_before = 1;
+
+ written = parport_ip32_fifo_write_block(p, buf, len);
+
+ /* Wait FIFO to empty. Timeout is proportional to FIFO_depth. */
+ parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);
+
+ /* Check for a potential residue */
+ written -= parport_ip32_get_fifo_residue(p, ECR_MODE_PPF);
+
+ /* Then, wait for BUSY to get low. */
+ if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))
+ printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",
+ p->name, __func__);
+
+stop:
+ /* Reset FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+}
+
+/*
+ * FIXME - Insert here parport_ip32_ecp_read_data().
+ */
+
+/**
+ * parport_ip32_ecp_write_data - write a block of data in ECP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: ignored
+ */
+static size_t parport_ip32_ecp_write_data(struct parport *p,
+ const void *buf, size_t len,
+ int flags)
+{
+ static unsigned int ready_before = 1;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ size_t written = 0;
+
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
+ return parport_ieee1284_ecp_write_data(p, buf, len, flags);
+
+ /* Negotiate to forward mode if necessary. */
+ if (physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+ /* Event 47: Set nInit high. */
+ parport_ip32_frob_control(p, DCR_nINIT | DCR_AUTOFD,
+ DCR_nINIT | DCR_AUTOFD);
+
+ /* Event 49: PError goes high. */
+ if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR)) {
+ printk(KERN_DEBUG PPIP32 "%s: PError timeout in %s",
+ p->name, __func__);
+ physport->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
+ return 0;
+ }
+ }
+
+ /* Reset FIFO, go in forward mode, and disable ackIntEn */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ parport_ip32_data_forward(p);
+ parport_ip32_disable_irq(p);
+ parport_ip32_set_mode(p, ECR_MODE_ECP);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* Wait for peripheral to become ready */
+ if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,
+ DSR_nBUSY | DSR_nFAULT)) {
+ /* Avoid to flood the logs */
+ if (ready_before)
+ printk(KERN_INFO PPIP32 "%s: not ready in %s\n",
+ p->name, __func__);
+ ready_before = 0;
+ goto stop;
+ }
+ ready_before = 1;
+
+ written = parport_ip32_fifo_write_block(p, buf, len);
+
+ /* Wait FIFO to empty. Timeout is proportional to FIFO_depth. */
+ parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);
+
+ /* Check for a potential residue */
+ written -= parport_ip32_get_fifo_residue(p, ECR_MODE_ECP);
+
+ /* Then, wait for BUSY to get low. */
+ if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))
+ printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",
+ p->name, __func__);
+
+stop:
+ /* Reset FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+}
+
+/*
+ * FIXME - Insert here parport_ip32_ecp_write_addr().
+ */
+
+/*--- Default parport operations ---------------------------------------*/
+
+static __initdata struct parport_operations parport_ip32_ops = {
+ .write_data = parport_ip32_write_data,
+ .read_data = parport_ip32_read_data,
+
+ .write_control = parport_ip32_write_control,
+ .read_control = parport_ip32_read_control,
+ .frob_control = parport_ip32_frob_control,
+
+ .read_status = parport_ip32_read_status,
+
+ .enable_irq = parport_ip32_enable_irq,
+ .disable_irq = parport_ip32_disable_irq,
+
+ .data_forward = parport_ip32_data_forward,
+ .data_reverse = parport_ip32_data_reverse,
+
+ .init_state = parport_ip32_init_state,
+ .save_state = parport_ip32_save_state,
+ .restore_state = parport_ip32_restore_state,
+
+ .epp_write_data = parport_ieee1284_epp_write_data,
+ .epp_read_data = parport_ieee1284_epp_read_data,
+ .epp_write_addr = parport_ieee1284_epp_write_addr,
+ .epp_read_addr = parport_ieee1284_epp_read_addr,
+
+ .ecp_write_data = parport_ieee1284_ecp_write_data,
+ .ecp_read_data = parport_ieee1284_ecp_read_data,
+ .ecp_write_addr = parport_ieee1284_ecp_write_addr,
+
+ .compat_write_data = parport_ieee1284_write_compat,
+ .nibble_read_data = parport_ieee1284_read_nibble,
+ .byte_read_data = parport_ieee1284_read_byte,
+
+ .owner = THIS_MODULE,
+};
+
+/*--- Device detection -------------------------------------------------*/
+
+/**
+ * parport_ip32_ecp_supported - check for an ECP port
+ * @p: pointer to the &parport structure
+ *
+ * Returns 1 if an ECP port is found, and 0 otherwise. This function actually
+ * checks if an Extended Control Register seems to be present. On successful
+ * return, the port is placed in SPP mode.
+ */
+static __init unsigned int parport_ip32_ecp_supported(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int ecr;
+
+ ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+ writeb(ecr, priv->regs.ecr);
+ if (readb(priv->regs.ecr) != (ecr | ECR_F_EMPTY))
+ goto fail;
+
+ pr_probe(p, "Found working ECR register\n");
+ parport_ip32_set_mode(p, ECR_MODE_SPP);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ return 1;
+
+fail:
+ pr_probe(p, "ECR register not found\n");
+ return 0;
+}
+
+/**
+ * parport_ip32_fifo_supported - check for FIFO parameters
+ * @p: pointer to the &parport structure
+ *
+ * Check for FIFO parameters of an Extended Capabilities Port. Returns 1 on
+ * success, and 0 otherwise. Adjust FIFO parameters in the parport structure.
+ * On return, the port is placed in SPP mode.
+ */
+static __init unsigned int parport_ip32_fifo_supported(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int configa, configb;
+ unsigned int pword;
+ unsigned int i;
+
+ /* Configuration mode */
+ parport_ip32_set_mode(p, ECR_MODE_CFG);
+ configa = readb(priv->regs.cnfgA);
+ configb = readb(priv->regs.cnfgB);
+
+ /* Find out PWord size */
+ switch (configa & CNFGA_ID_MASK) {
+ case CNFGA_ID_8:
+ pword = 1;
+ break;
+ case CNFGA_ID_16:
+ pword = 2;
+ break;
+ case CNFGA_ID_32:
+ pword = 4;
+ break;
+ default:
+ pr_probe(p, "Unknown implementation ID: 0x%0x\n",
+ (configa & CNFGA_ID_MASK) >> CNFGA_ID_SHIFT);
+ goto fail;
+ break;
+ }
+ if (pword != 1) {
+ pr_probe(p, "Unsupported PWord size: %u\n", pword);
+ goto fail;
+ }
+ priv->pword = pword;
+ pr_probe(p, "PWord is %u bits\n", 8 * priv->pword);
+
+ /* Check for compression support */
+ writeb(configb | CNFGB_COMPRESS, priv->regs.cnfgB);
+ if (readb(priv->regs.cnfgB) & CNFGB_COMPRESS)
+ pr_probe(p, "Hardware compression detected (unsupported)\n");
+ writeb(configb & ~CNFGB_COMPRESS, priv->regs.cnfgB);
+
+ /* Reset FIFO and go in test mode (no interrupt, no DMA) */
+ parport_ip32_set_mode(p, ECR_MODE_TST);
+
+ /* FIFO must be empty now */
+ if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {
+ pr_probe(p, "FIFO not reset\n");
+ goto fail;
+ }
+
+ /* Find out FIFO depth. */
+ priv->fifo_depth = 0;
+ for (i = 0; i < 1024; i++) {
+ if (readb(priv->regs.ecr) & ECR_F_FULL) {
+ /* FIFO full */
+ priv->fifo_depth = i;
+ break;
+ }
+ writeb((u8)i, priv->regs.fifo);
+ }
+ if (i >= 1024) {
+ pr_probe(p, "Can't fill FIFO\n");
+ goto fail;
+ }
+ if (!priv->fifo_depth) {
+ pr_probe(p, "Can't get FIFO depth\n");
+ goto fail;
+ }
+ pr_probe(p, "FIFO is %u PWords deep\n", priv->fifo_depth);
+
+ /* Enable interrupts */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+ /* Find out writeIntrThreshold: number of PWords we know we can write
+ * if we get an interrupt. */
+ priv->writeIntrThreshold = 0;
+ for (i = 0; i < priv->fifo_depth; i++) {
+ if (readb(priv->regs.fifo) != (u8)i) {
+ pr_probe(p, "Invalid data in FIFO\n");
+ goto fail;
+ }
+ if (!priv->writeIntrThreshold
+ && readb(priv->regs.ecr) & ECR_SERVINTR)
+ /* writeIntrThreshold reached */
+ priv->writeIntrThreshold = i + 1;
+ if (i + 1 < priv->fifo_depth
+ && readb(priv->regs.ecr) & ECR_F_EMPTY) {
+ /* FIFO empty before the last byte? */
+ pr_probe(p, "Data lost in FIFO\n");
+ goto fail;
+ }
+ }
+ if (!priv->writeIntrThreshold) {
+ pr_probe(p, "Can't get writeIntrThreshold\n");
+ goto fail;
+ }
+ pr_probe(p, "writeIntrThreshold is %u\n", priv->writeIntrThreshold);
+
+ /* FIFO must be empty now */
+ if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {
+ pr_probe(p, "Can't empty FIFO\n");
+ goto fail;
+ }
+
+ /* Reset FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ /* Set reverse direction (must be in PS2 mode) */
+ parport_ip32_data_reverse(p);
+ /* Test FIFO, no interrupt, no DMA */
+ parport_ip32_set_mode(p, ECR_MODE_TST);
+ /* Enable interrupts */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+ /* Find out readIntrThreshold: number of PWords we can read if we get
+ * an interrupt. */
+ priv->readIntrThreshold = 0;
+ for (i = 0; i < priv->fifo_depth; i++) {
+ writeb(0xaa, priv->regs.fifo);
+ if (readb(priv->regs.ecr) & ECR_SERVINTR) {
+ /* readIntrThreshold reached */
+ priv->readIntrThreshold = i + 1;
+ break;
+ }
+ }
+ if (!priv->readIntrThreshold) {
+ pr_probe(p, "Can't get readIntrThreshold\n");
+ goto fail;
+ }
+ pr_probe(p, "readIntrThreshold is %u\n", priv->readIntrThreshold);
+
+ /* Reset ECR */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_data_forward(p);
+ parport_ip32_set_mode(p, ECR_MODE_SPP);
+ return 1;
+
+fail:
+ priv->fifo_depth = 0;
+ parport_ip32_set_mode(p, ECR_MODE_SPP);
+ return 0;
+}
+
+/*--- Initialization code ----------------------------------------------*/
+
+/**
+ * parport_ip32_make_isa_registers - compute (ISA) register addresses
+ * @regs: pointer to &struct parport_ip32_regs to fill
+ * @base: base address of standard and EPP registers
+ * @base_hi: base address of ECP registers
+ * @regshift: how much to shift register offset by
+ *
+ * Compute register addresses, according to the ISA standard. The addresses
+ * of the standard and EPP registers are computed from address @base. The
+ * addresses of the ECP registers are computed from address @base_hi.
+ */
+static void __init
+parport_ip32_make_isa_registers(struct parport_ip32_regs *regs,
+ void __iomem *base, void __iomem *base_hi,
+ unsigned int regshift)
+{
+#define r_base(offset) ((u8 __iomem *)base + ((offset) << regshift))
+#define r_base_hi(offset) ((u8 __iomem *)base_hi + ((offset) << regshift))
+ *regs = (struct parport_ip32_regs){
+ .data = r_base(0),
+ .dsr = r_base(1),
+ .dcr = r_base(2),
+ .eppAddr = r_base(3),
+ .eppData0 = r_base(4),
+ .eppData1 = r_base(5),
+ .eppData2 = r_base(6),
+ .eppData3 = r_base(7),
+ .ecpAFifo = r_base(0),
+ .fifo = r_base_hi(0),
+ .cnfgA = r_base_hi(0),
+ .cnfgB = r_base_hi(1),
+ .ecr = r_base_hi(2)
+ };
+#undef r_base_hi
+#undef r_base
+}
+
+/**
+ * parport_ip32_probe_port - probe and register IP32 built-in parallel port
+ *
+ * Returns the new allocated &parport structure. On error, an error code is
+ * encoded in return value with the ERR_PTR function.
+ */
+static __init struct parport *parport_ip32_probe_port(void)
+{
+ struct parport_ip32_regs regs;
+ struct parport_ip32_private *priv = NULL;
+ struct parport_operations *ops = NULL;
+ struct parport *p = NULL;
+ int err;
+
+ parport_ip32_make_isa_registers(&regs, &mace->isa.parallel,
+ &mace->isa.ecp1284, 8 /* regshift */);
+
+ ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
+ priv = kmalloc(sizeof(struct parport_ip32_private), GFP_KERNEL);
+ p = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops);
+ if (ops == NULL || priv == NULL || p == NULL) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ p->base = MACE_BASE + offsetof(struct sgi_mace, isa.parallel);
+ p->base_hi = MACE_BASE + offsetof(struct sgi_mace, isa.ecp1284);
+ p->private_data = priv;
+
+ *ops = parport_ip32_ops;
+ *priv = (struct parport_ip32_private){
+ .regs = regs,
+ .dcr_writable = DCR_DIR | DCR_SELECT | DCR_nINIT |
+ DCR_AUTOFD | DCR_STROBE,
+ .irq_mode = PARPORT_IP32_IRQ_FWD,
+ };
+ init_completion(&priv->irq_complete);
+
+ /* Probe port. */
+ if (!parport_ip32_ecp_supported(p)) {
+ err = -ENODEV;
+ goto fail;
+ }
+ parport_ip32_dump_state(p, "begin init", 0);
+
+ /* We found what looks like a working ECR register. Simply assume
+ * that all modes are correctly supported. Enable basic modes. */
+ p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
+ p->modes |= PARPORT_MODE_TRISTATE;
+
+ if (!parport_ip32_fifo_supported(p)) {
+ printk(KERN_WARNING PPIP32
+ "%s: error: FIFO disabled\n", p->name);
+ /* Disable hardware modes depending on a working FIFO. */
+ features &= ~PARPORT_IP32_ENABLE_SPP;
+ features &= ~PARPORT_IP32_ENABLE_ECP;
+ /* DMA is not needed if FIFO is not supported. */
+ features &= ~PARPORT_IP32_ENABLE_DMA;
+ }
+
+ /* Request IRQ */
+ if (features & PARPORT_IP32_ENABLE_IRQ) {
+ int irq = MACEISA_PARALLEL_IRQ;
+ if (request_irq(irq, parport_ip32_interrupt, 0, p->name, p)) {
+ printk(KERN_WARNING PPIP32
+ "%s: error: IRQ disabled\n", p->name);
+ /* DMA cannot work without interrupts. */
+ features &= ~PARPORT_IP32_ENABLE_DMA;
+ } else {
+ pr_probe(p, "Interrupt support enabled\n");
+ p->irq = irq;
+ priv->dcr_writable |= DCR_IRQ;
+ }
+ }
+
+ /* Allocate DMA resources */
+ if (features & PARPORT_IP32_ENABLE_DMA) {
+ if (parport_ip32_dma_register())
+ printk(KERN_WARNING PPIP32
+ "%s: error: DMA disabled\n", p->name);
+ else {
+ pr_probe(p, "DMA support enabled\n");
+ p->dma = 0; /* arbitrary value != PARPORT_DMA_NONE */
+ p->modes |= PARPORT_MODE_DMA;
+ }
+ }
+
+ if (features & PARPORT_IP32_ENABLE_SPP) {
+ /* Enable compatibility FIFO mode */
+ p->ops->compat_write_data = parport_ip32_compat_write_data;
+ p->modes |= PARPORT_MODE_COMPAT;
+ pr_probe(p, "Hardware support for SPP mode enabled\n");
+ }
+ if (features & PARPORT_IP32_ENABLE_EPP) {
+ /* Set up access functions to use EPP hardware. */
+ p->ops->epp_read_data = parport_ip32_epp_read_data;
+ p->ops->epp_write_data = parport_ip32_epp_write_data;
+ p->ops->epp_read_addr = parport_ip32_epp_read_addr;
+ p->ops->epp_write_addr = parport_ip32_epp_write_addr;
+ p->modes |= PARPORT_MODE_EPP;
+ pr_probe(p, "Hardware support for EPP mode enabled\n");
+ }
+ if (features & PARPORT_IP32_ENABLE_ECP) {
+ /* Enable ECP FIFO mode */
+ p->ops->ecp_write_data = parport_ip32_ecp_write_data;
+ /* FIXME - not implemented */
+/* p->ops->ecp_read_data = parport_ip32_ecp_read_data; */
+/* p->ops->ecp_write_addr = parport_ip32_ecp_write_addr; */
+ p->modes |= PARPORT_MODE_ECP;
+ pr_probe(p, "Hardware support for ECP mode enabled\n");
+ }
+
+ /* Initialize the port with sensible values */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ parport_ip32_data_forward(p);
+ parport_ip32_disable_irq(p);
+ parport_ip32_write_data(p, 0x00);
+ parport_ip32_dump_state(p, "end init", 0);
+
+ /* Print out what we found */
+ printk(KERN_INFO "%s: SGI IP32 at 0x%lx (0x%lx)",
+ p->name, p->base, p->base_hi);
+ if (p->irq != PARPORT_IRQ_NONE)
+ printk(", irq %d", p->irq);
+ printk(" [");
+#define printmode(x) if (p->modes & PARPORT_MODE_##x) \
+ printk("%s%s", f++ ? "," : "", #x)
+ {
+ unsigned int f = 0;
+ printmode(PCSPP);
+ printmode(TRISTATE);
+ printmode(COMPAT);
+ printmode(EPP);
+ printmode(ECP);
+ printmode(DMA);
+ }
+#undef printmode
+ printk("]\n");
+
+ parport_announce_port(p);
+ return p;
+
+fail:
+ if (p)
+ parport_put_port(p);
+ kfree(priv);
+ kfree(ops);
+ return ERR_PTR(err);
+}
+
+/**
+ * parport_ip32_unregister_port - unregister a parallel port
+ * @p: pointer to the &struct parport
+ *
+ * Unregisters a parallel port and free previously allocated resources
+ * (memory, IRQ, ...).
+ */
+static __exit void parport_ip32_unregister_port(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport_operations *ops = p->ops;
+
+ parport_remove_port(p);
+ if (p->modes & PARPORT_MODE_DMA)
+ parport_ip32_dma_unregister();
+ if (p->irq != PARPORT_IRQ_NONE)
+ free_irq(p->irq, p);
+ parport_put_port(p);
+ kfree(priv);
+ kfree(ops);
+}
+
+/**
+ * parport_ip32_init - module initialization function
+ */
+static int __init parport_ip32_init(void)
+{
+ pr_info(PPIP32 "SGI IP32 built-in parallel port driver v0.6\n");
+ pr_debug1(PPIP32 "Compiled on %s, %s\n", __DATE__, __TIME__);
+ this_port = parport_ip32_probe_port();
+ return IS_ERR(this_port) ? PTR_ERR(this_port) : 0;
+}
+
+/**
+ * parport_ip32_exit - module termination function
+ */
+static void __exit parport_ip32_exit(void)
+{
+ parport_ip32_unregister_port(this_port);
+}
+
+/*--- Module stuff -----------------------------------------------------*/
+
+MODULE_AUTHOR("Arnaud Giersch <arnaud.giersch@free.fr>");
+MODULE_DESCRIPTION("SGI IP32 built-in parallel port driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.6"); /* update in parport_ip32_init() too */
+
+module_init(parport_ip32_init);
+module_exit(parport_ip32_exit);
+
+module_param(verbose_probing, bool, S_IRUGO);
+MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialization");
+
+module_param(features, uint, S_IRUGO);
+MODULE_PARM_DESC(features,
+ "Bit mask of features to enable"
+ ", bit 0: IRQ support"
+ ", bit 1: DMA support"
+ ", bit 2: hardware SPP mode"
+ ", bit 3: hardware EPP mode"
+ ", bit 4: hardware ECP mode");
+
+/*--- Inform (X)Emacs about preferred coding style ---------------------*/
+/*
+ * Local Variables:
+ * mode: c
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * tab-width: 8
+ * fill-column: 78
+ * ispell-local-dictionary: "american"
+ * End:
+ */
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 76dd077e3184..166de3507780 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -329,9 +329,9 @@ static int __devinit parport_register (struct pci_dev *dev,
if (priv->num_par == ARRAY_SIZE (priv->port)) {
printk (KERN_WARNING
- "parport_serial: %s: only %u parallel ports "
+ "parport_serial: %s: only %zu parallel ports "
"supported (%d reported)\n", pci_name (dev),
- ARRAY_SIZE (priv->port), card->numports);
+ ARRAY_SIZE(priv->port), card->numports);
break;
}
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index b62aee8de3cb..ea83b70e0de2 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -199,7 +199,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
if (port->physport->ieee1284.phase != IEEE1284_PH_HBUSY_DAVAIL) {
if (belen != len) {
- printk (KERN_DEBUG "%s: Device ID was %d bytes"
+ printk (KERN_DEBUG "%s: Device ID was %zd bytes"
" while device told it would be %d"
" bytes\n",
port->name, len, belen);
@@ -214,7 +214,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
if (buffer[len-1] == ';') {
printk (KERN_DEBUG "%s: Device ID reading stopped"
" before device told data not available. "
- "Current idlen %d of %d, len bytes %02X %02X\n",
+ "Current idlen %u of %u, len bytes %02X %02X\n",
port->name, current_idlen, numidlens,
length[0], length[1]);
goto done;
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 6f50cc9323d9..6912399d0937 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -55,13 +55,21 @@ config DASD_DIAG
Disks under VM. If you are not running under VM or unsure what it is,
say "N".
+config DASD_EER
+ tristate "Extended error reporting (EER)"
+ depends on DASD
+ help
+ This driver provides a character device interface to the
+ DASD extended error reporting. This is only needed if you want to
+ use applications written for the EER facility.
+
config DASD_CMB
tristate "Compatibility interface for DASD channel measurement blocks"
depends on DASD
help
- This driver provides an additional interface to the channel measurement
- facility, which is normally accessed though sysfs, with a set of
- ioctl functions specific to the dasd driver.
+ This driver provides an additional interface to the channel
+ measurement facility, which is normally accessed though sysfs, with
+ a set of ioctl functions specific to the dasd driver.
This is only needed if you want to use applications written for
linux-2.4 dasd channel measurement facility interface.
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
index 58c6780134f7..0c0d871e8f51 100644
--- a/drivers/s390/block/Makefile
+++ b/drivers/s390/block/Makefile
@@ -5,6 +5,7 @@
dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
dasd_diag_mod-objs := dasd_diag.o
+dasd_eer_mod-objs := dasd_eer.o
dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
dasd_genhd.o dasd_erp.o
@@ -13,5 +14,6 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o
obj-$(CONFIG_DASD_CMB) += dasd_cmb.o
+obj-$(CONFIG_DASD_EER) += dasd_eer.o
obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
obj-$(CONFIG_DCSSBLK) += dcssblk.o
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index abdf1ee633e7..08c88fcd8963 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
+#include <linux/notifier.h>
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
@@ -57,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data);
+static void dasd_disable_eer(struct dasd_device *device);
/*
* SECTION: Operations on the device structure.
@@ -151,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device)
static inline void
dasd_state_known_to_new(struct dasd_device * device)
{
+ /* disable extended error reporting for this device */
+ dasd_disable_eer(device);
/* Forget the discipline information. */
device->discipline = NULL;
device->state = DASD_STATE_NEW;
@@ -867,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device)
struct dasd_ccw_req *cqr;
struct list_head *l, *n;
+ /* first of all call extended error reporting */
+ dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
+
device->stopped &= ~DASD_STOPPED_PENDING;
/* restart all 'running' IO on queue */
@@ -1086,6 +1093,19 @@ restart:
}
goto restart;
}
+
+ /* first of all call extended error reporting */
+ if (device->eer && cqr->status == DASD_CQR_FAILED) {
+ dasd_write_eer_trigger(DASD_EER_FATALERROR,
+ device, cqr);
+
+ /* restart request */
+ cqr->status = DASD_CQR_QUEUED;
+ cqr->retries = 255;
+ device->stopped |= DASD_STOPPED_QUIESCE;
+ goto restart;
+ }
+
/* Process finished ERP request. */
if (cqr->refers) {
__dasd_process_erp(device, cqr);
@@ -1223,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
/* check FAILFAST */
if (device->stopped & ~DASD_STOPPED_PENDING &&
- test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) {
+ test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+ (!device->eer)) {
cqr->status = DASD_CQR_FAILED;
dasd_schedule_bh(device);
}
@@ -1965,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
switch (event) {
case CIO_GONE:
case CIO_NO_PATH:
+ /* first of all call extended error reporting */
+ dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
+
if (device->state < DASD_STATE_BASIC)
break;
/* Device is active. We want to keep it. */
@@ -2022,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
put_driver(drv);
}
+/*
+ * notifications for extended error reports
+ */
+static struct notifier_block *dasd_eer_chain;
+
+int
+dasd_register_eer_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_register(&dasd_eer_chain, nb);
+}
+
+int
+dasd_unregister_eer_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_unregister(&dasd_eer_chain, nb);
+}
+
+/*
+ * Notify the registered error reporting module of a problem
+ */
+void
+dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ if (device->eer) {
+ struct dasd_eer_trigger temp;
+ temp.id = id;
+ temp.device = device;
+ temp.cqr = cqr;
+ notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
+ (void *)&temp);
+ }
+}
+
+/*
+ * Tell the registered error reporting module to disable error reporting for
+ * a given device and to cleanup any private data structures on that device.
+ */
+static void
+dasd_disable_eer(struct dasd_device *device)
+{
+ notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
+}
+
+
static int __init
dasd_init(void)
{
@@ -2103,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
+EXPORT_SYMBOL(dasd_register_eer_notifier);
+EXPORT_SYMBOL(dasd_unregister_eer_notifier);
+EXPORT_SYMBOL(dasd_write_eer_trigger);
+
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 4ee0f934e325..c811380b9079 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1108,6 +1108,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
case 0x0B:
DEV_MESSAGE(KERN_WARNING, device, "%s",
"FORMAT F - Volume is suspended duplex");
+ /* call extended error reporting (EER) */
+ dasd_write_eer_trigger(DASD_EER_PPRCSUSPEND, device,
+ erp->refers);
break;
case 0x0C:
DEV_MESSAGE(KERN_WARNING, device, "%s",
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index bc3823d35223..e15dd7978050 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -29,6 +29,7 @@
#define DASD_ECKD_CCW_PSF 0x27
#define DASD_ECKD_CCW_RSSD 0x3e
#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+#define DASD_ECKD_CCW_SNSS 0x54
#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
#define DASD_ECKD_CCW_WRITE_MT 0x85
#define DASD_ECKD_CCW_READ_MT 0x86
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
new file mode 100644
index 000000000000..f70cd7716b24
--- /dev/null
+++ b/drivers/s390/block/dasd_eer.c
@@ -0,0 +1,1090 @@
+/*
+ * character device driver for extended error reporting
+ *
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * extended error reporting for DASD ECKD devices
+ * Author(s): Stefan Weinhuber <wein@de.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/notifier.h>
+
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
+#include <asm/ebcdic.h>
+
+#include "dasd_int.h"
+#include "dasd_eckd.h"
+
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Stefan Weinhuber <wein@de.ibm.com>");
+MODULE_DESCRIPTION("DASD extended error reporting module");
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif /* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eer):"
+
+
+
+
+
+/*****************************************************************************/
+/* the internal buffer */
+/*****************************************************************************/
+
+/*
+ * The internal buffer is meant to store obaque blobs of data, so it doesn't
+ * know of higher level concepts like triggers.
+ * It consists of a number of pages that are used as a ringbuffer. Each data
+ * blob is stored in a simple record that consists of an integer, which
+ * contains the size of the following data, and the data bytes themselfes.
+ *
+ * To allow for multiple independent readers we create one internal buffer
+ * each time the device is opened and destroy the buffer when the file is
+ * closed again.
+ *
+ * One record can be written to a buffer by using the functions
+ * - dasd_eer_start_record (one time per record to write the size to the buffer
+ * and reserve the space for the data)
+ * - dasd_eer_write_buffer (one or more times per record to write the data)
+ * The data can be written in several steps but you will have to compute
+ * the total size up front for the invocation of dasd_eer_start_record.
+ * If the ringbuffer is full, dasd_eer_start_record will remove the required
+ * number of old records.
+ *
+ * A record is typically read in two steps, first read the integer that
+ * specifies the size of the following data, then read the data.
+ * Both can be done by
+ * - dasd_eer_read_buffer
+ *
+ * For all mentioned functions you need to get the bufferlock first and keep it
+ * until a complete record is written or read.
+ */
+
+
+/*
+ * Alle information necessary to keep track of an internal buffer is kept in
+ * a struct eerbuffer. The buffer specific to a file pointer is strored in
+ * the private_data field of that file. To be able to write data to all
+ * existing buffers, each buffer is also added to the bufferlist.
+ * If the user doesn't want to read a complete record in one go, we have to
+ * keep track of the rest of the record. residual stores the number of bytes
+ * that are still to deliver. If the rest of the record is invalidated between
+ * two reads then residual will be set to -1 so that the next read will fail.
+ * All entries in the eerbuffer structure are protected with the bufferlock.
+ * To avoid races between writing to a buffer on the one side and creating
+ * and destroying buffers on the other side, the bufferlock must also be used
+ * to protect the bufferlist.
+ */
+
+struct eerbuffer {
+ struct list_head list;
+ char **buffer;
+ int buffersize;
+ int buffer_page_count;
+ int head;
+ int tail;
+ int residual;
+};
+
+LIST_HEAD(bufferlist);
+
+static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
+
+DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
+
+/*
+ * How many free bytes are available on the buffer.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_get_free_bytes(struct eerbuffer *eerb)
+{
+ if (eerb->head < eerb->tail) {
+ return eerb->tail - eerb->head - 1;
+ } else
+ return eerb->buffersize - eerb->head + eerb->tail -1;
+}
+
+/*
+ * How many bytes of buffer space are used.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_get_filled_bytes(struct eerbuffer *eerb)
+{
+
+ if (eerb->head >= eerb->tail) {
+ return eerb->head - eerb->tail;
+ } else
+ return eerb->buffersize - eerb->tail + eerb->head;
+}
+
+/*
+ * The dasd_eer_write_buffer function just copies count bytes of data
+ * to the buffer. Make sure to call dasd_eer_start_record first, to
+ * make sure that enough free space is available.
+ * needs to be called with bufferlock held
+ */
+static void
+dasd_eer_write_buffer(struct eerbuffer *eerb, int count, char *data)
+{
+
+ unsigned long headindex,localhead;
+ unsigned long rest, len;
+ char *nextdata;
+
+ nextdata = data;
+ rest = count;
+ while (rest > 0) {
+ headindex = eerb->head / PAGE_SIZE;
+ localhead = eerb->head % PAGE_SIZE;
+ len = min(rest, (PAGE_SIZE - localhead));
+ memcpy(eerb->buffer[headindex]+localhead, nextdata, len);
+ nextdata += len;
+ rest -= len;
+ eerb->head += len;
+ if ( eerb->head == eerb->buffersize )
+ eerb->head = 0; /* wrap around */
+ if (eerb->head > eerb->buffersize) {
+ MESSAGE(KERN_ERR, "%s", "runaway buffer head.");
+ BUG();
+ }
+ }
+}
+
+/*
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_read_buffer(struct eerbuffer *eerb, int count, char *data)
+{
+
+ unsigned long tailindex,localtail;
+ unsigned long rest, len, finalcount;
+ char *nextdata;
+
+ finalcount = min(count, dasd_eer_get_filled_bytes(eerb));
+ nextdata = data;
+ rest = finalcount;
+ while (rest > 0) {
+ tailindex = eerb->tail / PAGE_SIZE;
+ localtail = eerb->tail % PAGE_SIZE;
+ len = min(rest, (PAGE_SIZE - localtail));
+ memcpy(nextdata, eerb->buffer[tailindex]+localtail, len);
+ nextdata += len;
+ rest -= len;
+ eerb->tail += len;
+ if ( eerb->tail == eerb->buffersize )
+ eerb->tail = 0; /* wrap around */
+ if (eerb->tail > eerb->buffersize) {
+ MESSAGE(KERN_ERR, "%s", "runaway buffer tail.");
+ BUG();
+ }
+ }
+ return finalcount;
+}
+
+/*
+ * Whenever you want to write a blob of data to the internal buffer you
+ * have to start by using this function first. It will write the number
+ * of bytes that will be written to the buffer. If necessary it will remove
+ * old records to make room for the new one.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_start_record(struct eerbuffer *eerb, int count)
+{
+ int tailcount;
+ if (count + sizeof(count) > eerb->buffersize)
+ return -ENOMEM;
+ while (dasd_eer_get_free_bytes(eerb) < count + sizeof(count)) {
+ if (eerb->residual > 0) {
+ eerb->tail += eerb->residual;
+ if (eerb->tail >= eerb->buffersize)
+ eerb->tail -= eerb->buffersize;
+ eerb->residual = -1;
+ }
+ dasd_eer_read_buffer(eerb, sizeof(tailcount),
+ (char*)(&tailcount));
+ eerb->tail += tailcount;
+ if (eerb->tail >= eerb->buffersize)
+ eerb->tail -= eerb->buffersize;
+ }
+ dasd_eer_write_buffer(eerb, sizeof(count), (char*)(&count));
+
+ return 0;
+};
+
+/*
+ * release pages that are not used anymore
+ */
+static void
+dasd_eer_free_buffer_pages(char **buf, int no_pages)
+{
+ int i;
+
+ for (i = 0; i < no_pages; ++i) {
+ free_page((unsigned long)buf[i]);
+ }
+}
+
+/*
+ * allocate a new set of memory pages
+ */
+static int
+dasd_eer_allocate_buffer_pages(char **buf, int no_pages)
+{
+ int i;
+
+ for (i = 0; i < no_pages; ++i) {
+ buf[i] = (char *) get_zeroed_page(GFP_KERNEL);
+ if (!buf[i]) {
+ dasd_eer_free_buffer_pages(buf, i);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/*
+ * empty the buffer by resetting head and tail
+ * In case there is a half read data blob in the buffer, we set residual
+ * to -1 to indicate that the remainder of the blob is lost.
+ */
+static void
+dasd_eer_purge_buffer(struct eerbuffer *eerb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bufferlock, flags);
+ if (eerb->residual > 0)
+ eerb->residual = -1;
+ eerb->tail=0;
+ eerb->head=0;
+ spin_unlock_irqrestore(&bufferlock, flags);
+}
+
+/*
+ * set the size of the buffer, newsize is the new number of pages to be used
+ * we don't try to copy any data back an forth, so any resize will also purge
+ * the buffer
+ */
+static int
+dasd_eer_resize_buffer(struct eerbuffer *eerb, int newsize)
+{
+ int i, oldcount, reuse;
+ char **new;
+ char **old;
+ unsigned long flags;
+
+ if (newsize < 1)
+ return -EINVAL;
+ if (eerb->buffer_page_count == newsize) {
+ /* documented behaviour is that any successfull invocation
+ * will purge all records */
+ dasd_eer_purge_buffer(eerb);
+ return 0;
+ }
+ new = kmalloc(newsize*sizeof(char*), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ reuse=min(eerb->buffer_page_count, newsize);
+ for (i = 0; i < reuse; ++i) {
+ new[i] = eerb->buffer[i];
+ }
+ if (eerb->buffer_page_count < newsize) {
+ if (dasd_eer_allocate_buffer_pages(
+ &new[eerb->buffer_page_count],
+ newsize - eerb->buffer_page_count)) {
+ kfree(new);
+ return -ENOMEM;
+ }
+ }
+
+ spin_lock_irqsave(&bufferlock, flags);
+ old = eerb->buffer;
+ eerb->buffer = new;
+ if (eerb->residual > 0)
+ eerb->residual = -1;
+ eerb->tail = 0;
+ eerb->head = 0;
+ oldcount = eerb->buffer_page_count;
+ eerb->buffer_page_count = newsize;
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ if (oldcount > newsize) {
+ for (i = newsize; i < oldcount; ++i) {
+ free_page((unsigned long)old[i]);
+ }
+ }
+ kfree(old);
+
+ return 0;
+}
+
+
+/*****************************************************************************/
+/* The extended error reporting functionality */
+/*****************************************************************************/
+
+/*
+ * When a DASD device driver wants to report an error, it calls the
+ * function dasd_eer_write_trigger (via a notifier mechanism) and gives the
+ * respective trigger ID as parameter.
+ * Currently there are four kinds of triggers:
+ *
+ * DASD_EER_FATALERROR: all kinds of unrecoverable I/O problems
+ * DASD_EER_PPRCSUSPEND: PPRC was suspended
+ * DASD_EER_NOPATH: There is no path to the device left.
+ * DASD_EER_STATECHANGE: The state of the device has changed.
+ *
+ * For the first three triggers all required information can be supplied by
+ * the caller. For these triggers a record is written by the function
+ * dasd_eer_write_standard_trigger.
+ *
+ * When dasd_eer_write_trigger is called to write a DASD_EER_STATECHANGE
+ * trigger, we have to gather the necessary sense data first. We cannot queue
+ * the necessary SNSS (sense subsystem status) request immediatly, since we
+ * are likely to run in a deadlock situation. Instead, we schedule a
+ * work_struct that calls the function dasd_eer_sense_subsystem_status to
+ * create and start an SNSS request asynchronously.
+ *
+ * To avoid memory allocations at runtime, the necessary memory is allocated
+ * when the extended error reporting is enabled for a device (by
+ * dasd_eer_probe). There is one private eer data structure for each eer
+ * enabled DASD device. It contains memory for the work_struct, one SNSS cqr
+ * and a flags field that is used to coordinate the use of the cqr. The call
+ * to write a state change trigger can come in at any time, so we have one flag
+ * CQR_IN_USE that protects the cqr itself. When this flag indicates that the
+ * cqr is currently in use, dasd_eer_sense_subsystem_status cannot start a
+ * second request but sets the SNSS_REQUESTED flag instead.
+ *
+ * When the request is finished, the callback function dasd_eer_SNSS_cb
+ * is called. This function will invoke the function
+ * dasd_eer_write_SNSS_trigger to finally write the trigger. It will also
+ * check the SNSS_REQUESTED flag and if it is set it will call
+ * dasd_eer_sense_subsystem_status again.
+ *
+ * To avoid race conditions during the handling of the lock, the flags must
+ * be protected by the snsslock.
+ */
+
+struct dasd_eer_private {
+ struct dasd_ccw_req *cqr;
+ unsigned long flags;
+ struct work_struct worker;
+};
+
+static void dasd_eer_destroy(struct dasd_device *device,
+ struct dasd_eer_private *eer);
+static int
+dasd_eer_write_trigger(struct dasd_eer_trigger *trigger);
+static void dasd_eer_sense_subsystem_status(void *data);
+static int dasd_eer_notify(struct notifier_block *self,
+ unsigned long action, void *data);
+
+struct workqueue_struct *dasd_eer_workqueue;
+
+#define SNSS_DATA_SIZE 44
+static spinlock_t snsslock = SPIN_LOCK_UNLOCKED;
+
+#define DASD_EER_BUSID_SIZE 10
+struct dasd_eer_header {
+ __u32 total_size;
+ __u32 trigger;
+ __u64 tv_sec;
+ __u64 tv_usec;
+ char busid[DASD_EER_BUSID_SIZE];
+} __attribute__ ((packed));
+
+static struct notifier_block dasd_eer_nb = {
+ .notifier_call = dasd_eer_notify,
+};
+
+/*
+ * flags for use with dasd_eer_private
+ */
+#define CQR_IN_USE 0
+#define SNSS_REQUESTED 1
+
+/*
+ * This function checks if extended error reporting is available for a given
+ * dasd_device. If yes, then it creates and returns a struct dasd_eer,
+ * otherwise it returns an -EPERM error pointer.
+ */
+struct dasd_eer_private *
+dasd_eer_probe(struct dasd_device *device)
+{
+ struct dasd_eer_private *private;
+
+ if (!(device && device->discipline
+ && !strcmp(device->discipline->name, "ECKD"))) {
+ return ERR_PTR(-EPERM);
+ }
+ /* allocate the private data structure */
+ private = (struct dasd_eer_private *)kmalloc(
+ sizeof(struct dasd_eer_private), GFP_KERNEL);
+ if (!private) {
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_WORK(&private->worker, dasd_eer_sense_subsystem_status,
+ (void *)device);
+ private->cqr = dasd_kmalloc_request("ECKD",
+ 1 /* SNSS */ ,
+ SNSS_DATA_SIZE ,
+ device);
+ if (!private->cqr) {
+ kfree(private);
+ return ERR_PTR(-ENOMEM);
+ }
+ private->flags = 0;
+ return private;
+};
+
+/*
+ * If our private SNSS request is queued, remove it from the
+ * dasd ccw queue so we can free the requests memory.
+ */
+static void
+dasd_eer_dequeue_SNSS_request(struct dasd_device *device,
+ struct dasd_eer_private *eer)
+{
+ struct list_head *lst, *nxt;
+ struct dasd_ccw_req *cqr, *erpcqr;
+ dasd_erp_fn_t erp_fn;
+
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ list_for_each_safe(lst, nxt, &device->ccw_queue) {
+ cqr = list_entry(lst, struct dasd_ccw_req, list);
+ /* we are looking for two kinds or requests */
+ /* first kind: our SNSS request: */
+ if (cqr == eer->cqr) {
+ if (cqr->status == DASD_CQR_IN_IO)
+ device->discipline->term_IO(cqr);
+ list_del(&cqr->list);
+ break;
+ }
+ /* second kind: ERP requests for our SNSS request */
+ if (cqr->refers) {
+ /* If this erp request chain ends in our cqr, then */
+ /* cal the erp_postaction to clean it up */
+ erpcqr = cqr;
+ while (erpcqr->refers) {
+ erpcqr = erpcqr->refers;
+ }
+ if (erpcqr == eer->cqr) {
+ erp_fn = device->discipline->erp_postaction(
+ cqr);
+ erp_fn(cqr);
+ }
+ continue;
+ }
+ }
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+/*
+ * This function dismantles a struct dasd_eer that was created by
+ * dasd_eer_probe. Since we want to free our private data structure,
+ * we must make sure that the memory is not in use anymore.
+ * We have to flush the work queue and remove a possible SNSS request
+ * from the dasd queue.
+ */
+static void
+dasd_eer_destroy(struct dasd_device *device, struct dasd_eer_private *eer)
+{
+ flush_workqueue(dasd_eer_workqueue);
+ dasd_eer_dequeue_SNSS_request(device, eer);
+ dasd_kfree_request(eer->cqr, device);
+ kfree(eer);
+};
+
+/*
+ * enable the extended error reporting for a particular device
+ */
+static int
+dasd_eer_enable_on_device(struct dasd_device *device)
+{
+ void *eer;
+ if (!device)
+ return -ENODEV;
+ if (device->eer)
+ return 0;
+ if (!try_module_get(THIS_MODULE)) {
+ return -EINVAL;
+ }
+ eer = (void *)dasd_eer_probe(device);
+ if (IS_ERR(eer)) {
+ module_put(THIS_MODULE);
+ return PTR_ERR(eer);
+ }
+ device->eer = eer;
+ return 0;
+}
+
+/*
+ * enable the extended error reporting for a particular device
+ */
+static int
+dasd_eer_disable_on_device(struct dasd_device *device)
+{
+ struct dasd_eer_private *eer = device->eer;
+
+ if (!device)
+ return -ENODEV;
+ if (!device->eer)
+ return 0;
+ device->eer = NULL;
+ dasd_eer_destroy(device,eer);
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+/*
+ * Set extended error reporting (eer)
+ * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
+ */
+static int
+dasd_ioctl_set_eer(struct block_device *bdev, int no, long args)
+{
+ struct dasd_device *device;
+ int intval;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (bdev != bdev->bd_contains)
+ /* Error-reporting is not allowed for partitions */
+ return -EINVAL;
+ if (get_user(intval, (int __user *) args))
+ return -EFAULT;
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return -ENODEV;
+
+ intval = (intval != 0);
+ DEV_MESSAGE (KERN_DEBUG, device,
+ "set eer on device to %d", intval);
+ if (intval)
+ return dasd_eer_enable_on_device(device);
+ else
+ return dasd_eer_disable_on_device(device);
+}
+
+/*
+ * Get value of extended error reporting.
+ * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
+ */
+static int
+dasd_ioctl_get_eer(struct block_device *bdev, int no, long args)
+{
+ struct dasd_device *device;
+
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return -ENODEV;
+ return put_user((device->eer != NULL), (int __user *) args);
+}
+
+/*
+ * The following function can be used for those triggers that have
+ * all necessary data available when the function is called.
+ * If the parameter cqr is not NULL, the chain of requests will be searched
+ * for valid sense data, and all valid sense data sets will be added to
+ * the triggers data.
+ */
+static int
+dasd_eer_write_standard_trigger(int trigger, struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ struct dasd_ccw_req *temp_cqr;
+ int data_size;
+ struct timeval tv;
+ struct dasd_eer_header header;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ /* go through cqr chain and count the valid sense data sets */
+ temp_cqr = cqr;
+ data_size = 0;
+ while (temp_cqr) {
+ if (temp_cqr->irb.esw.esw0.erw.cons)
+ data_size += 32;
+ temp_cqr = temp_cqr->refers;
+ }
+
+ header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
+ header.trigger = trigger;
+ do_gettimeofday(&tv);
+ header.tv_sec = tv.tv_sec;
+ header.tv_usec = tv.tv_usec;
+ strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+
+ spin_lock_irqsave(&bufferlock, flags);
+ list_for_each_entry(eerb, &bufferlist, list) {
+ dasd_eer_start_record(eerb, header.total_size);
+ dasd_eer_write_buffer(eerb, sizeof(header), (char*)(&header));
+ temp_cqr = cqr;
+ while (temp_cqr) {
+ if (temp_cqr->irb.esw.esw0.erw.cons)
+ dasd_eer_write_buffer(eerb, 32, cqr->irb.ecw);
+ temp_cqr = temp_cqr->refers;
+ }
+ dasd_eer_write_buffer(eerb, 4,"EOR");
+ }
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ wake_up_interruptible(&dasd_eer_read_wait_queue);
+
+ return 0;
+}
+
+/*
+ * This function writes a DASD_EER_STATECHANGE trigger.
+ */
+static void
+dasd_eer_write_SNSS_trigger(struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ int data_size;
+ int snss_rc;
+ struct timeval tv;
+ struct dasd_eer_header header;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+ if (snss_rc)
+ data_size = 0;
+ else
+ data_size = SNSS_DATA_SIZE;
+
+ header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
+ header.trigger = DASD_EER_STATECHANGE;
+ do_gettimeofday(&tv);
+ header.tv_sec = tv.tv_sec;
+ header.tv_usec = tv.tv_usec;
+ strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+
+ spin_lock_irqsave(&bufferlock, flags);
+ list_for_each_entry(eerb, &bufferlist, list) {
+ dasd_eer_start_record(eerb, header.total_size);
+ dasd_eer_write_buffer(eerb, sizeof(header),(char*)(&header));
+ if (!snss_rc)
+ dasd_eer_write_buffer(eerb, SNSS_DATA_SIZE, cqr->data);
+ dasd_eer_write_buffer(eerb, 4,"EOR");
+ }
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ wake_up_interruptible(&dasd_eer_read_wait_queue);
+}
+
+/*
+ * callback function for use with SNSS request
+ */
+static void
+dasd_eer_SNSS_cb(struct dasd_ccw_req *cqr, void *data)
+{
+ struct dasd_device *device;
+ struct dasd_eer_private *private;
+ unsigned long irqflags;
+
+ device = (struct dasd_device *)data;
+ private = (struct dasd_eer_private *)device->eer;
+ dasd_eer_write_SNSS_trigger(device, cqr);
+ spin_lock_irqsave(&snsslock, irqflags);
+ if(!test_and_clear_bit(SNSS_REQUESTED, &private->flags)) {
+ clear_bit(CQR_IN_USE, &private->flags);
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ return;
+ };
+ clear_bit(CQR_IN_USE, &private->flags);
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ dasd_eer_sense_subsystem_status(device);
+ return;
+}
+
+/*
+ * clean a used cqr before using it again
+ */
+static void
+dasd_eer_clean_SNSS_request(struct dasd_ccw_req *cqr)
+{
+ struct ccw1 *cpaddr = cqr->cpaddr;
+ void *data = cqr->data;
+
+ memset(cqr, 0, sizeof(struct dasd_ccw_req));
+ memset(cpaddr, 0, sizeof(struct ccw1));
+ memset(data, 0, SNSS_DATA_SIZE);
+ cqr->cpaddr = cpaddr;
+ cqr->data = data;
+ strncpy((char *) &cqr->magic, "ECKD", 4);
+ ASCEBC((char *) &cqr->magic, 4);
+ set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+}
+
+/*
+ * build and start an SNSS request
+ * This function is called from a work queue so we have to
+ * pass the dasd_device pointer as a void pointer.
+ */
+static void
+dasd_eer_sense_subsystem_status(void *data)
+{
+ struct dasd_device *device;
+ struct dasd_eer_private *private;
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+ unsigned long irqflags;
+
+ device = (struct dasd_device *)data;
+ private = (struct dasd_eer_private *)device->eer;
+ if (!private) /* device not eer enabled any more */
+ return;
+ cqr = private->cqr;
+ spin_lock_irqsave(&snsslock, irqflags);
+ if(test_and_set_bit(CQR_IN_USE, &private->flags)) {
+ set_bit(SNSS_REQUESTED, &private->flags);
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ return;
+ };
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ dasd_eer_clean_SNSS_request(cqr);
+ cqr->device = device;
+ cqr->retries = 255;
+ cqr->expires = 10 * HZ;
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = DASD_ECKD_CCW_SNSS;
+ ccw->count = SNSS_DATA_SIZE;
+ ccw->flags = 0;
+ ccw->cda = (__u32)(addr_t)cqr->data;
+
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+ cqr->callback = dasd_eer_SNSS_cb;
+ cqr->callback_data = (void *)device;
+ dasd_add_request_head(cqr);
+
+ return;
+}
+
+/*
+ * This function is called for all triggers. It calls the appropriate
+ * function that writes the actual trigger records.
+ */
+static int
+dasd_eer_write_trigger(struct dasd_eer_trigger *trigger)
+{
+ int rc;
+ struct dasd_eer_private *private = trigger->device->eer;
+
+ switch (trigger->id) {
+ case DASD_EER_FATALERROR:
+ case DASD_EER_PPRCSUSPEND:
+ rc = dasd_eer_write_standard_trigger(
+ trigger->id, trigger->device, trigger->cqr);
+ break;
+ case DASD_EER_NOPATH:
+ rc = dasd_eer_write_standard_trigger(
+ trigger->id, trigger->device, NULL);
+ break;
+ case DASD_EER_STATECHANGE:
+ if (queue_work(dasd_eer_workqueue, &private->worker)) {
+ rc=0;
+ } else {
+ /* If the work_struct was already queued, it can't
+ * be queued again. But this is OK since we don't
+ * need to have it queued twice.
+ */
+ rc = -EBUSY;
+ }
+ break;
+ default: /* unknown trigger, so we write it without any sense data */
+ rc = dasd_eer_write_standard_trigger(
+ trigger->id, trigger->device, NULL);
+ break;
+ }
+ return rc;
+}
+
+/*
+ * This function is registered with the dasd device driver and gets called
+ * for all dasd eer notifications.
+ */
+static int dasd_eer_notify(struct notifier_block *self,
+ unsigned long action, void *data)
+{
+ switch (action) {
+ case DASD_EER_DISABLE:
+ dasd_eer_disable_on_device((struct dasd_device *)data);
+ break;
+ case DASD_EER_TRIGGER:
+ dasd_eer_write_trigger((struct dasd_eer_trigger *)data);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+
+/*****************************************************************************/
+/* the device operations */
+/*****************************************************************************/
+
+/*
+ * On the one side we need a lock to access our internal buffer, on the
+ * other side a copy_to_user can sleep. So we need to copy the data we have
+ * to transfer in a readbuffer, which is protected by the readbuffer_mutex.
+ */
+static char readbuffer[PAGE_SIZE];
+DECLARE_MUTEX(readbuffer_mutex);
+
+
+static int
+dasd_eer_open(struct inode *inp, struct file *filp)
+{
+ struct eerbuffer *eerb;
+ unsigned long flags;
+
+ eerb = kmalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+ eerb->head = 0;
+ eerb->tail = 0;
+ eerb->residual = 0;
+ eerb->buffer_page_count = 1;
+ eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE;
+ eerb->buffer = kmalloc(eerb->buffer_page_count*sizeof(char*),
+ GFP_KERNEL);
+ if (!eerb->buffer)
+ return -ENOMEM;
+ if (dasd_eer_allocate_buffer_pages(eerb->buffer,
+ eerb->buffer_page_count)) {
+ kfree(eerb->buffer);
+ return -ENOMEM;
+ }
+ filp->private_data = eerb;
+ spin_lock_irqsave(&bufferlock, flags);
+ list_add(&eerb->list, &bufferlist);
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ return nonseekable_open(inp,filp);
+}
+
+static int
+dasd_eer_close(struct inode *inp, struct file *filp)
+{
+ struct eerbuffer *eerb;
+ unsigned long flags;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ spin_lock_irqsave(&bufferlock, flags);
+ list_del(&eerb->list);
+ spin_unlock_irqrestore(&bufferlock, flags);
+ dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count);
+ kfree(eerb->buffer);
+ kfree(eerb);
+
+ return 0;
+}
+
+static long
+dasd_eer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int intval;
+ struct eerbuffer *eerb;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ switch (cmd) {
+ case DASD_EER_PURGE:
+ dasd_eer_purge_buffer(eerb);
+ return 0;
+ case DASD_EER_SETBUFSIZE:
+ if (get_user(intval, (int __user *)arg))
+ return -EFAULT;
+ return dasd_eer_resize_buffer(eerb, intval);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static ssize_t
+dasd_eer_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
+{
+ int tc,rc;
+ int tailcount,effective_count;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ if(down_interruptible(&readbuffer_mutex))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&bufferlock, flags);
+
+ if (eerb->residual < 0) { /* the remainder of this record */
+ /* has been deleted */
+ eerb->residual = 0;
+ spin_unlock_irqrestore(&bufferlock, flags);
+ up(&readbuffer_mutex);
+ return -EIO;
+ } else if (eerb->residual > 0) {
+ /* OK we still have a second half of a record to deliver */
+ effective_count = min(eerb->residual, (int)count);
+ eerb->residual -= effective_count;
+ } else {
+ tc = 0;
+ while (!tc) {
+ tc = dasd_eer_read_buffer(eerb,
+ sizeof(tailcount), (char*)(&tailcount));
+ if (!tc) {
+ /* no data available */
+ spin_unlock_irqrestore(&bufferlock, flags);
+ up(&readbuffer_mutex);
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ rc = wait_event_interruptible(
+ dasd_eer_read_wait_queue,
+ eerb->head != eerb->tail);
+ if (rc) {
+ return rc;
+ }
+ if(down_interruptible(&readbuffer_mutex))
+ return -ERESTARTSYS;
+ spin_lock_irqsave(&bufferlock, flags);
+ }
+ }
+ WARN_ON(tc != sizeof(tailcount));
+ effective_count = min(tailcount,(int)count);
+ eerb->residual = tailcount - effective_count;
+ }
+
+ tc = dasd_eer_read_buffer(eerb, effective_count, readbuffer);
+ WARN_ON(tc != effective_count);
+
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ if (copy_to_user(buf, readbuffer, effective_count)) {
+ up(&readbuffer_mutex);
+ return -EFAULT;
+ }
+
+ up(&readbuffer_mutex);
+ return effective_count;
+}
+
+static unsigned int
+dasd_eer_poll (struct file *filp, poll_table *ptable)
+{
+ unsigned int mask;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ poll_wait(filp, &dasd_eer_read_wait_queue, ptable);
+ spin_lock_irqsave(&bufferlock, flags);
+ if (eerb->head != eerb->tail)
+ mask = POLLIN | POLLRDNORM ;
+ else
+ mask = 0;
+ spin_unlock_irqrestore(&bufferlock, flags);
+ return mask;
+}
+
+static struct file_operations dasd_eer_fops = {
+ .open = &dasd_eer_open,
+ .release = &dasd_eer_close,
+ .unlocked_ioctl = &dasd_eer_ioctl,
+ .compat_ioctl = &dasd_eer_ioctl,
+ .read = &dasd_eer_read,
+ .poll = &dasd_eer_poll,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice dasd_eer_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "dasd_eer",
+ .fops = &dasd_eer_fops,
+};
+
+
+/*****************************************************************************/
+/* Init and exit */
+/*****************************************************************************/
+
+static int
+__init dasd_eer_init(void)
+{
+ int rc;
+
+ dasd_eer_workqueue = create_singlethread_workqueue("dasd_eer");
+ if (!dasd_eer_workqueue) {
+ MESSAGE(KERN_ERR , "%s", "dasd_eer_init could not "
+ "create workqueue \n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = dasd_register_eer_notifier(&dasd_eer_nb);
+ if (rc) {
+ MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
+ "register error reporting");
+ goto queue;
+ }
+
+ dasd_ioctl_no_register(THIS_MODULE, BIODASDEERSET, dasd_ioctl_set_eer);
+ dasd_ioctl_no_register(THIS_MODULE, BIODASDEERGET, dasd_ioctl_get_eer);
+
+ /* we don't need our own character device,
+ * so we just register as misc device */
+ rc = misc_register(&dasd_eer_dev);
+ if (rc) {
+ MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
+ "register misc device");
+ goto unregister;
+ }
+
+ return 0;
+
+unregister:
+ dasd_unregister_eer_notifier(&dasd_eer_nb);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
+ dasd_ioctl_set_eer);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
+ dasd_ioctl_get_eer);
+queue:
+ destroy_workqueue(dasd_eer_workqueue);
+out:
+ return rc;
+
+}
+module_init(dasd_eer_init);
+
+static void
+__exit dasd_eer_exit(void)
+{
+ dasd_unregister_eer_notifier(&dasd_eer_nb);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
+ dasd_ioctl_set_eer);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
+ dasd_ioctl_get_eer);
+ destroy_workqueue(dasd_eer_workqueue);
+
+ WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+}
+module_exit(dasd_eer_exit);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index c20af9874500..d1b08fa13fd2 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -275,6 +275,34 @@ struct dasd_discipline {
extern struct dasd_discipline *dasd_diag_discipline_pointer;
+
+/*
+ * Notification numbers for extended error reporting notifications:
+ * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's
+ * eer pointer) is freed. The error reporting module needs to do all necessary
+ * cleanup steps.
+ * The DASD_EER_TRIGGER notification sends the actual error reports (triggers).
+ */
+#define DASD_EER_DISABLE 0
+#define DASD_EER_TRIGGER 1
+
+/* Trigger IDs for extended error reporting DASD_EER_TRIGGER notification */
+#define DASD_EER_FATALERROR 1
+#define DASD_EER_NOPATH 2
+#define DASD_EER_STATECHANGE 3
+#define DASD_EER_PPRCSUSPEND 4
+
+/*
+ * The dasd_eer_trigger structure contains all data that we need to send
+ * along with an DASD_EER_TRIGGER notification.
+ */
+struct dasd_eer_trigger {
+ unsigned int id;
+ struct dasd_device *device;
+ struct dasd_ccw_req *cqr;
+};
+
+
struct dasd_device {
/* Block device stuff. */
struct gendisk *gdp;
@@ -288,6 +316,9 @@ struct dasd_device {
unsigned long flags; /* per device flags */
unsigned short features; /* copy of devmap-features (read-only!) */
+ /* extended error reporting stuff (eer) */
+ void *eer;
+
/* Device discipline stuff. */
struct dasd_discipline *discipline;
char *private;
@@ -488,6 +519,12 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_auto_online (struct ccw_driver *);
+int dasd_register_eer_notifier(struct notifier_block *);
+int dasd_unregister_eer_notifier(struct notifier_block *);
+void dasd_write_eer_trigger(unsigned int , struct dasd_device *,
+ struct dasd_ccw_req *);
+
+
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 44e4b4bb1c5a..3e75095f35d0 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -68,6 +68,6 @@ extern void *chsc_get_chp_desc(struct subchannel*, int);
extern int chsc_enable_facility(int);
-#define to_channelpath(dev) container_of(dev, struct channel_path, dev)
+#define to_channelpath(device) container_of(device, struct channel_path, dev)
#endif
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 0d38f0f2ae29..ee4265d7a8c9 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -892,20 +892,20 @@ config SERIAL_VR41XX_CONSOLE
a console on a serial port, say Y. Otherwise, say N.
config SERIAL_JSM
- tristate "Digi International NEO PCI Support"
- depends on PCI && BROKEN
- select SERIAL_CORE
- help
- This is a driver for Digi International's Neo series
- of cards which provide multiple serial ports. You would need
- something like this to connect more than two modems to your Linux
- box, for instance in order to become a dial-in server. This driver
- supports PCI boards only.
- If you have a card like this, say Y here and read the file
- <file:Documentation/jsm.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called jsm.
+ tristate "Digi International NEO PCI Support"
+ depends on PCI
+ select SERIAL_CORE
+ help
+ This is a driver for Digi International's Neo series
+ of cards which provide multiple serial ports. You would need
+ something like this to connect more than two modems to your Linux
+ box, for instance in order to become a dial-in server. This driver
+ supports PCI boards only.
+ If you have a card like this, say Y here and read the file
+ <file:Documentation/jsm.txt>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jsm.
config SERIAL_SGI_IOC4
tristate "SGI IOC4 controller serial support"
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 18753193f59b..dfc1e86d3aa1 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -380,7 +380,6 @@ struct neo_uart_struct {
extern struct uart_driver jsm_uart_driver;
extern struct board_ops jsm_neo_ops;
extern int jsm_debug;
-extern int jsm_rawreadok;
/*************************************************************************
*
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 7e56c7824194..b1b66e71d281 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -49,11 +49,8 @@ struct uart_driver jsm_uart_driver = {
};
int jsm_debug;
-int jsm_rawreadok;
module_param(jsm_debug, int, 0);
-module_param(jsm_rawreadok, int, 0);
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
-MODULE_PARM_DESC(jsm_rawreadok, "Bypass flip buffers on input");
static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 6fa0d62d6f68..4d48b625cd3d 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -20,8 +20,10 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
- *
+ * Ananda Venkatarman <mansarov@us.ibm.com>
+ * Modifications:
+ * 01/19/06: changed jsm_input routine to use the dynamically allocated
+ * tty_buffer changes. Contributors: Scott Kilau and Ananda V.
***********************************************************************/
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -497,16 +499,15 @@ void jsm_input(struct jsm_channel *ch)
{
struct jsm_board *bd;
struct tty_struct *tp;
+ struct tty_ldisc *ld;
u32 rmask;
u16 head;
u16 tail;
int data_len;
unsigned long lock_flags;
- int flip_len;
+ int flip_len = 0;
int len = 0;
int n = 0;
- char *buf = NULL;
- char *buf2 = NULL;
int s = 0;
int i = 0;
@@ -574,56 +575,50 @@ void jsm_input(struct jsm_channel *ch)
/*
* If the rxbuf is empty and we are not throttled, put as much
- * as we can directly into the linux TTY flip buffer.
- * The jsm_rawreadok case takes advantage of carnal knowledge that
- * the char_buf and the flag_buf are next to each other and
- * are each of (2 * TTY_FLIPBUF_SIZE) size.
+ * as we can directly into the linux TTY buffer.
*
- * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
- *actually still uses the flag buffer, so you can't
- *use it for input data
*/
- if (jsm_rawreadok) {
- if (tp->real_raw)
- flip_len = MYFLIPLEN;
- else
- flip_len = 2 * TTY_FLIPBUF_SIZE;
- } else
- flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+ flip_len = TTY_FLIPBUF_SIZE;
len = min(data_len, flip_len);
len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+ ld = tty_ldisc_ref(tp);
- if (len <= 0) {
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
- return;
- }
+ /*
+ * If the DONT_FLIP flag is on, don't flush our buffer, and act
+ * like the ld doesn't have any space to put the data right now.
+ */
+ if (test_bit(TTY_DONT_FLIP, &tp->flags))
+ len = 0;
/*
- * If we're bypassing flip buffers on rx, we can blast it
- * right into the beginning of the buffer.
+ * If we were unable to get a reference to the ld,
+ * don't flush our buffer, and act like the ld doesn't
+ * have any space to put the data right now.
*/
- if (jsm_rawreadok) {
- if (tp->real_raw) {
- if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "JSM - FLIPBUF in use. delaying input\n");
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- return;
- }
- ch->ch_flags |= CH_FLIPBUF_IN_USE;
- buf = ch->ch_bd->flipbuf;
- buf2 = NULL;
- } else {
- buf = tp->flip.char_buf;
- buf2 = tp->flip.flag_buf;
- }
+ if (!ld) {
+ len = 0;
} else {
- buf = tp->flip.char_buf_ptr;
- buf2 = tp->flip.flag_buf_ptr;
+ /*
+ * If ld doesn't have a pointer to a receive_buf function,
+ * flush the data, then act like the ld doesn't have any
+ * space to put the data right now.
+ */
+ if (!ld->receive_buf) {
+ ch->ch_r_head = ch->ch_r_tail;
+ len = 0;
+ }
}
+ if (len <= 0) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+ if (ld)
+ tty_ldisc_deref(ld);
+ return;
+ }
+
+ len = tty_buffer_request_room(tp, len);
n = len;
/*
@@ -638,121 +633,47 @@ void jsm_input(struct jsm_channel *ch)
if (s <= 0)
break;
- memcpy(buf, ch->ch_rqueue + tail, s);
-
- /* buf2 is only set when port isn't raw */
- if (buf2)
- memcpy(buf2, ch->ch_equeue + tail, s);
-
- tail += s;
- buf += s;
- if (buf2)
- buf2 += s;
- n -= s;
- /* Flip queue if needed */
- tail &= rmask;
- }
+ /*
+ * If conditions are such that ld needs to see all
+ * UART errors, we will have to walk each character
+ * and error byte and send them to the buffer one at
+ * a time.
+ */
- /*
- * In high performance mode, we don't have to update
- * flag_buf or any of the counts or pointers into flip buf.
- */
- if (!jsm_rawreadok) {
if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
- for (i = 0; i < len; i++) {
+ for (i = 0; i < s; i++) {
/*
* Give the Linux ld the flags in the
* format it likes.
*/
- if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
- tp->flip.flag_buf_ptr[i] = TTY_BREAK;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
- tp->flip.flag_buf_ptr[i] = TTY_PARITY;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
- tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+ if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK);
+ else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
+ else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
else
- tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
}
} else {
- memset(tp->flip.flag_buf_ptr, 0, len);
+ tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
}
-
- tp->flip.char_buf_ptr += len;
- tp->flip.flag_buf_ptr += len;
- tp->flip.count += len;
- }
- else if (!tp->real_raw) {
- if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
- for (i = 0; i < len; i++) {
- /*
- * Give the Linux ld the flags in the
- * format it likes.
- */
- if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
- tp->flip.flag_buf_ptr[i] = TTY_BREAK;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
- tp->flip.flag_buf_ptr[i] = TTY_PARITY;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
- tp->flip.flag_buf_ptr[i] = TTY_FRAME;
- else
- tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
- }
- } else
- memset(tp->flip.flag_buf, 0, len);
+ tail += s;
+ n -= s;
+ /* Flip queue if needed */
+ tail &= rmask;
}
- /*
- * If we're doing raw reads, jam it right into the
- * line disc bypassing the flip buffers.
- */
- if (jsm_rawreadok) {
- if (tp->real_raw) {
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
-
- jsm_check_queue_flow_control(ch);
-
- /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+ ch->ch_r_tail = tail & rmask;
+ ch->ch_e_tail = tail & rmask;
+ jsm_check_queue_flow_control(ch);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ /* Tell the tty layer its okay to "eat" the data now */
+ tty_flip_buffer_push(tp);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n",
- __LINE__, len, ch->ch_bd->boardnum);
- tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
-
- /* Allow use of channel flip buffer again */
- spin_lock_irqsave(&ch->ch_lock, lock_flags);
- ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
- } else {
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
-
- jsm_check_queue_flow_control(ch);
-
- /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n",
- __LINE__, len, ch->ch_bd->boardnum);
-
- tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
- }
- } else {
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
-
- jsm_check_queue_flow_control(ch);
-
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__);
- tty_schedule_flip(tp);
- }
+ if (ld)
+ tty_ldisc_deref(ld);
jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
}
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index d957a3a9edf1..0ef648fa4b2d 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -350,8 +350,7 @@ static inline void receive_chars(struct mcf_serial *info)
}
tty_insert_flip_char(tty, ch, flag);
}
-
- schedule_work(&tty->flip.work);
+ tty_flip_buffer_push(tty);
return;
}
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index f6704688ee8c..5578a9dd04e8 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -3558,10 +3558,16 @@ static void ixj_write_frame(IXJ *j)
}
/* Add word 0 to G.729 frames for the 8021. Right now we don't do VAD/CNG */
if (j->play_codec == G729 && (cnt == 0 || cnt == 10 || cnt == 20)) {
- if(j->write_buffer_rp + cnt == 0 && j->write_buffer_rp + cnt + 1 == 0 && j->write_buffer_rp + cnt + 2 == 0 &&
- j->write_buffer_rp + cnt + 3 == 0 && j->write_buffer_rp + cnt + 4 == 0 && j->write_buffer_rp + cnt + 5 == 0 &&
- j->write_buffer_rp + cnt + 6 == 0 && j->write_buffer_rp + cnt + 7 == 0 && j->write_buffer_rp + cnt + 8 == 0 &&
- j->write_buffer_rp + cnt + 9 == 0) {
+ if (j->write_buffer_rp[cnt] == 0 &&
+ j->write_buffer_rp[cnt + 1] == 0 &&
+ j->write_buffer_rp[cnt + 2] == 0 &&
+ j->write_buffer_rp[cnt + 3] == 0 &&
+ j->write_buffer_rp[cnt + 4] == 0 &&
+ j->write_buffer_rp[cnt + 5] == 0 &&
+ j->write_buffer_rp[cnt + 6] == 0 &&
+ j->write_buffer_rp[cnt + 7] == 0 &&
+ j->write_buffer_rp[cnt + 8] == 0 &&
+ j->write_buffer_rp[cnt + 9] == 0) {
/* someone is trying to write silence lets make this a type 0 frame. */
outb_p(0x00, j->DSPbase + 0x0C);
outb_p(0x00, j->DSPbase + 0x0D);