summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/accessibility/Kconfig23
-rw-r--r--drivers/accessibility/Makefile1
-rw-r--r--drivers/accessibility/braille/Makefile1
-rw-r--r--drivers/accessibility/braille/braille_console.c397
-rw-r--r--drivers/atm/ambassador.c19
-rw-r--r--drivers/atm/ambassador.h2
-rw-r--r--drivers/base/node.c2
-rw-r--r--drivers/block/brd.c19
-rw-r--r--drivers/bluetooth/hci_ldisc.c13
-rw-r--r--drivers/char/agp/agp.h2
-rw-r--r--drivers/char/amiserial.c30
-rw-r--r--drivers/char/applicom.c4
-rw-r--r--drivers/char/consolemap.c1
-rw-r--r--drivers/char/cyclades.c432
-rw-r--r--drivers/char/drm/drmP.h8
-rw-r--r--drivers/char/drm/drm_sysfs.c2
-rw-r--r--drivers/char/drm/i830_dma.c18
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/i830_irq.c8
-rw-r--r--drivers/char/drm/i915_dma.c4
-rw-r--r--drivers/char/drm/i915_drv.h2
-rw-r--r--drivers/char/drm/radeon_cp.c2
-rw-r--r--drivers/char/ds1286.c3
-rw-r--r--drivers/char/epca.c315
-rw-r--r--drivers/char/esp.c611
-rw-r--r--drivers/char/generic_serial.c18
-rw-r--r--drivers/char/hpet.c10
-rw-r--r--drivers/char/hvsi.c52
-rw-r--r--drivers/char/ip2/i2ellis.c194
-rw-r--r--drivers/char/ip2/i2ellis.h58
-rw-r--r--drivers/char/ip2/i2hw.h6
-rw-r--r--drivers/char/ip2/i2lib.c141
-rw-r--r--drivers/char/ip2/i2os.h127
-rw-r--r--drivers/char/ip2/ip2main.c89
-rw-r--r--drivers/char/isicom.c171
-rw-r--r--drivers/char/istallion.c22
-rw-r--r--drivers/char/keyboard.c4
-rw-r--r--drivers/char/mmtimer.c400
-rw-r--r--drivers/char/moxa.c2999
-rw-r--r--drivers/char/moxa.h304
-rw-r--r--drivers/char/mxser.c346
-rw-r--r--drivers/char/mxser.h137
-rw-r--r--drivers/char/n_hdlc.c35
-rw-r--r--drivers/char/n_r3964.c33
-rw-r--r--drivers/char/n_tty.c160
-rw-r--r--drivers/char/nozomi.c17
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c23
-rw-r--r--drivers/char/pty.c32
-rw-r--r--drivers/char/rio/cirrus.h210
-rw-r--r--drivers/char/rio/rio_linux.c10
-rw-r--r--drivers/char/rio/rio_linux.h6
-rw-r--r--drivers/char/rio/riocmd.c19
-rw-r--r--drivers/char/rio/rioctrl.c37
-rw-r--r--drivers/char/rio/riointr.c5
-rw-r--r--drivers/char/rio/rioparam.c70
-rw-r--r--drivers/char/rio/riotty.c25
-rw-r--r--drivers/char/riscom8.c706
-rw-r--r--drivers/char/rocket.c43
-rw-r--r--drivers/char/serial167.c25
-rw-r--r--drivers/char/snsc.c18
-rw-r--r--drivers/char/snsc_event.c6
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/specialix.c111
-rw-r--r--drivers/char/stallion.c17
-rw-r--r--drivers/char/sx.c35
-rw-r--r--drivers/char/synclink.c31
-rw-r--r--drivers/char/synclink_gt.c80
-rw-r--r--drivers/char/synclinkmp.c41
-rw-r--r--drivers/char/tty_io.c372
-rw-r--r--drivers/char/tty_ioctl.c126
-rw-r--r--drivers/char/viocons.c12
-rw-r--r--drivers/char/vt.c21
-rw-r--r--drivers/char/vt_ioctl.c452
-rw-r--r--drivers/gpio/gpiolib.c4
-rw-r--r--drivers/hwmon/ads7828.c2
-rw-r--r--drivers/input/serio/serport.c2
-rw-r--r--drivers/isdn/capi/capi.c9
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c15
-rw-r--r--drivers/isdn/i4l/isdn_tty.c30
-rw-r--r--drivers/md/md.c112
-rw-r--r--drivers/md/raid1.c27
-rw-r--r--drivers/md/raid10.c29
-rw-r--r--drivers/md/raid5.c33
-rw-r--r--drivers/media/common/Makefile1
-rw-r--r--drivers/media/video/bt8xx/bttvp.h2
-rw-r--r--drivers/media/video/usbvideo/vicam.c6
-rw-r--r--drivers/mfd/asic3.c6
-rw-r--r--drivers/mfd/sm501.c4
-rw-r--r--drivers/misc/kgdbts.c2
-rw-r--r--drivers/net/3c505.c30
-rw-r--r--drivers/net/3c505.h1
-rw-r--r--drivers/net/3c509.c47
-rw-r--r--drivers/net/3c515.c64
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/arm/Kconfig8
-rw-r--r--drivers/net/arm/Makefile1
-rw-r--r--drivers/net/arm/ixp4xx_eth.c1265
-rw-r--r--drivers/net/bfin_mac.c296
-rw-r--r--drivers/net/bfin_mac.h2
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/fec_mpc52xx.c23
-rw-r--r--drivers/net/gianfar.c27
-rw-r--r--drivers/net/gianfar.h1
-rw-r--r--drivers/net/gianfar_mii.c38
-rw-r--r--drivers/net/gianfar_mii.h3
-rw-r--r--drivers/net/hamradio/6pack.c36
-rw-r--r--drivers/net/hamradio/mkiss.c15
-rw-r--r--drivers/net/irda/irtty-sir.c95
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/phy/smsc.c83
-rw-r--r--drivers/net/ppp_async.c9
-rw-r--r--drivers/net/ppp_synctty.c9
-rw-r--r--drivers/net/r8169.c8
-rw-r--r--drivers/net/s2io.c337
-rw-r--r--drivers/net/s2io.h82
-rw-r--r--drivers/net/sfc/Kconfig12
-rw-r--r--drivers/net/sfc/Makefile5
-rw-r--r--drivers/net/sfc/bitfield.h508
-rw-r--r--drivers/net/sfc/boards.c167
-rw-r--r--drivers/net/sfc/boards.h26
-rw-r--r--drivers/net/sfc/efx.c2208
-rw-r--r--drivers/net/sfc/efx.h67
-rw-r--r--drivers/net/sfc/enum.h50
-rw-r--r--drivers/net/sfc/ethtool.c460
-rw-r--r--drivers/net/sfc/ethtool.h27
-rw-r--r--drivers/net/sfc/falcon.c2722
-rw-r--r--drivers/net/sfc/falcon.h130
-rw-r--r--drivers/net/sfc/falcon_hwdefs.h1135
-rw-r--r--drivers/net/sfc/falcon_io.h243
-rw-r--r--drivers/net/sfc/falcon_xmac.c585
-rw-r--r--drivers/net/sfc/gmii.h195
-rw-r--r--drivers/net/sfc/i2c-direct.c381
-rw-r--r--drivers/net/sfc/i2c-direct.h91
-rw-r--r--drivers/net/sfc/mac.h33
-rw-r--r--drivers/net/sfc/mdio_10g.c282
-rw-r--r--drivers/net/sfc/mdio_10g.h232
-rw-r--r--drivers/net/sfc/net_driver.h883
-rw-r--r--drivers/net/sfc/phy.h48
-rw-r--r--drivers/net/sfc/rx.c875
-rw-r--r--drivers/net/sfc/rx.h29
-rw-r--r--drivers/net/sfc/sfe4001.c252
-rw-r--r--drivers/net/sfc/spi.h71
-rw-r--r--drivers/net/sfc/tenxpress.c434
-rw-r--r--drivers/net/sfc/tx.c452
-rw-r--r--drivers/net/sfc/tx.h24
-rw-r--r--drivers/net/sfc/workarounds.h56
-rw-r--r--drivers/net/sfc/xenpack.h62
-rw-r--r--drivers/net/sfc/xfp_phy.c132
-rw-r--r--drivers/net/sis190.c136
-rw-r--r--drivers/net/slip.c13
-rw-r--r--drivers/net/wan/pc300_tty.c24
-rw-r--r--drivers/net/wan/x25_asy.c279
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig12
-rw-r--r--drivers/net/wireless/strip.c66
-rw-r--r--drivers/parport/ieee1284.c4
-rw-r--r--drivers/parport/parport_gsc.c4
-rw-r--r--drivers/parport/parport_pc.c8
-rw-r--r--drivers/s390/char/con3215.c5
-rw-r--r--drivers/s390/char/sclp_config.c17
-rw-r--r--drivers/s390/char/sclp_tty.c4
-rw-r--r--drivers/s390/char/sclp_vt220.c6
-rw-r--r--drivers/s390/char/tty3270.c3
-rw-r--r--drivers/s390/cio/ccwgroup.c103
-rw-r--r--drivers/s390/cio/cio.c9
-rw-r--r--drivers/s390/cio/cio.h3
-rw-r--r--drivers/s390/cio/cmf.c11
-rw-r--r--drivers/s390/cio/css.c10
-rw-r--r--drivers/s390/cio/device.c17
-rw-r--r--drivers/s390/cio/device_fsm.c10
-rw-r--r--drivers/s390/cio/device_ops.c2
-rw-r--r--drivers/s390/cio/qdio.c8
-rw-r--r--drivers/s390/kvm/kvm_virtio.c23
-rw-r--r--drivers/s390/net/cu3088.c20
-rw-r--r--drivers/s390/net/lcs.c3
-rw-r--r--drivers/s390/net/netiucv.c3
-rw-r--r--drivers/s390/net/qeth_core.h50
-rw-r--r--drivers/s390/net/qeth_core_main.c200
-rw-r--r--drivers/s390/net/qeth_l2_main.c30
-rw-r--r--drivers/s390/net/qeth_l3.h3
-rw-r--r--drivers/s390/net/qeth_l3_main.c30
-rw-r--r--drivers/sbus/char/cpwatchdog.c2
-rw-r--r--drivers/sbus/char/uctrl.c4
-rw-r--r--drivers/serial/68328serial.c21
-rw-r--r--drivers/serial/68360serial.c28
-rw-r--r--drivers/serial/8250_early.c2
-rw-r--r--drivers/serial/Kconfig43
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/bfin_5xx.c4
-rw-r--r--drivers/serial/bfin_sport_uart.c614
-rw-r--r--drivers/serial/bfin_sport_uart.h63
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/crisv10.c31
-rw-r--r--drivers/serial/ioc3_serial.c36
-rw-r--r--drivers/serial/ioc4_serial.c32
-rw-r--r--drivers/serial/kgdboc.c6
-rw-r--r--drivers/serial/mcfserial.c22
-rw-r--r--drivers/serial/mpc52xx_uart.c2
-rw-r--r--drivers/serial/netx-serial.c1
-rw-r--r--drivers/serial/s3c2410.c6
-rw-r--r--drivers/serial/sa1100.c4
-rw-r--r--drivers/serial/serial_core.c54
-rw-r--r--drivers/serial/sh-sci.c2
-rw-r--r--drivers/serial/sn_console.c2
-rw-r--r--drivers/serial/uartlite.c2
-rw-r--r--drivers/serial/ucc_uart.c4
-rw-r--r--drivers/spi/atmel_spi.c29
-rw-r--r--drivers/usb/gadget/serial.c10
-rw-r--r--drivers/usb/serial/digi_acceleport.c3
-rw-r--r--drivers/usb/serial/usb-serial.c129
-rw-r--r--drivers/usb/serial/whiteheat.c4
-rw-r--r--drivers/video/Kconfig5
-rw-r--r--drivers/video/pxafb.c1297
-rw-r--r--drivers/video/pxafb.h70
-rw-r--r--drivers/w1/w1_log.h2
220 files changed, 22418 insertions, 6671 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 80f0ec91e2c..59f33fa6af3 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -84,6 +84,8 @@ source "drivers/memstick/Kconfig"
source "drivers/leds/Kconfig"
+source "drivers/accessibility/Kconfig"
+
source "drivers/infiniband/Kconfig"
source "drivers/edac/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index e5e394a7e6c..f65deda72d6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
+obj-$(CONFIG_ACCESSIBILITY) += accessibility/
obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_MCA) += mca/
diff --git a/drivers/accessibility/Kconfig b/drivers/accessibility/Kconfig
new file mode 100644
index 00000000000..1264c4b9809
--- /dev/null
+++ b/drivers/accessibility/Kconfig
@@ -0,0 +1,23 @@
+menuconfig ACCESSIBILITY
+ bool "Accessibility support"
+ ---help---
+ Enable a submenu where accessibility items may be enabled.
+
+ If unsure, say N.
+
+if ACCESSIBILITY
+config A11Y_BRAILLE_CONSOLE
+ bool "Console on braille device"
+ depends on VT
+ depends on SERIAL_CORE_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl,ttyS0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # ACCESSIBILITY
diff --git a/drivers/accessibility/Makefile b/drivers/accessibility/Makefile
new file mode 100644
index 00000000000..72b01a46546
--- /dev/null
+++ b/drivers/accessibility/Makefile
@@ -0,0 +1 @@
+obj-y += braille/
diff --git a/drivers/accessibility/braille/Makefile b/drivers/accessibility/braille/Makefile
new file mode 100644
index 00000000000..2e9f16c9134
--- /dev/null
+++ b/drivers/accessibility/braille/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
new file mode 100644
index 00000000000..0a5f6b2114c
--- /dev/null
+++ b/drivers/accessibility/braille/braille_console.c
@@ -0,0 +1,397 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org>
+ *
+ * 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 the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("samuel.thibault@ens-lyon.org");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+
+static void beep(unsigned int freq)
+{
+ if (sound)
+ kd_mksound(freq, HZ/10);
+}
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i = 0; i < WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum |= 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ braille_co->write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i < WIDTH; i++) {
+ u16 glyph = screen_glyph(vc,
+ 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch (val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ if (vc->vc_num != fg_console)
+ break;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1],
+ (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Called from printk.c when console=brl is given
+ */
+
+int braille_register_console(struct console *console, int index,
+ char *console_options, char *braille_options)
+{
+ int ret;
+ if (!console_options)
+ /* Only support VisioBraille for now */
+ console_options = "57600o8";
+ if (braille_co)
+ return -ENODEV;
+ if (console->setup) {
+ ret = console->setup(console, console_options);
+ if (ret != 0)
+ return ret;
+ }
+ console->flags |= CON_ENABLED;
+ console->index = index;
+ braille_co = console;
+ return 0;
+}
+
+int braille_unregister_console(struct console *console)
+{
+ if (braille_co != console)
+ return -EINVAL;
+ braille_co = NULL;
+ return 0;
+}
+
+static int __init braille_init(void)
+{
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+
+console_initcall(braille_init);
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 5aa12b011a9..6adb72a2f87 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/poison.h>
#include <linux/bitrev.h>
+#include <linux/mutex.h>
#include <asm/atomic.h>
#include <asm/io.h>
@@ -1177,7 +1178,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
vcc->tx_frame_bits = tx_frame_bits;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer on the channel already, just modify rate...
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@@ -1203,7 +1204,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
schedule();
}
dev->txer[vci].tx_present = 1;
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
if (rxtp->traffic_class != ATM_NONE) {
@@ -1211,7 +1212,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
vcc->rx_info.pool = pool;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
/* grow RX buffer pool */
if (!dev->rxq[pool].buffers_wanted)
dev->rxq[pool].buffers_wanted = rx_lats;
@@ -1237,7 +1238,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
schedule();
// this link allows RX frames through
dev->rxer[vci] = atm_vcc;
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// indicate readiness
@@ -1262,7 +1263,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
command cmd;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer still on the channel, just modify rate... XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@@ -1277,7 +1278,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
dev->txer[vci].tx_present = 0;
while (command_do (dev, &cmd))
schedule();
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// disable RXing
@@ -1287,7 +1288,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
// this is (the?) one reason why we need the amb_vcc struct
unsigned char pool = vcc->rx_info.pool;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->txer[vci].tx_present) {
// TXer still on the channel, just go to pool zero XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
@@ -1314,7 +1315,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
dev->rxq[pool].buffers_wanted = 0;
drain_rx_pool (dev, pool);
}
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// free our structure
@@ -2188,7 +2189,7 @@ static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev)
// semaphore for txer/rxer modifications - we cannot use a
// spinlock as the critical region needs to switch processes
- init_MUTEX (&dev->vcc_sf);
+ mutex_init(&dev->vcc_sf);
// queue manipulation spinlocks; we want atomic reads and
// writes to the queue descriptors (handles IRQ and SMP)
// consider replacing "int pending" -> "atomic_t available"
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index ff2a303cbe0..df55fa8387d 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -638,7 +638,7 @@ struct amb_dev {
amb_txq txq;
amb_rxq rxq[NUM_RX_POOLS];
- struct semaphore vcc_sf;
+ struct mutex vcc_sf;
amb_tx_info txer[NUM_VCS];
struct atm_vcc * rxer[NUM_VCS];
unsigned int tx_avail;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 12fde2d03d6..39f3d1b3a21 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -77,6 +77,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
"Node %d PageTables: %8lu kB\n"
"Node %d NFS_Unstable: %8lu kB\n"
"Node %d Bounce: %8lu kB\n"
+ "Node %d WritebackTmp: %8lu kB\n"
"Node %d Slab: %8lu kB\n"
"Node %d SReclaimable: %8lu kB\n"
"Node %d SUnreclaim: %8lu kB\n",
@@ -99,6 +100,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
nid, K(node_page_state(nid, NR_PAGETABLE)),
nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
nid, K(node_page_state(nid, NR_BOUNCE)),
+ nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index e8e38faeafd..a196ef7f147 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -387,10 +387,14 @@ static struct block_device_operations brd_fops = {
*/
static int rd_nr;
int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
+static int max_part;
+static int part_shift;
module_param(rd_nr, int, 0);
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
module_param(rd_size, int, 0);
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
+module_param(max_part, int, 0);
+MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
@@ -435,11 +439,11 @@ static struct brd_device *brd_alloc(int i)
blk_queue_max_sectors(brd->brd_queue, 1024);
blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
- disk = brd->brd_disk = alloc_disk(1);
+ disk = brd->brd_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;
disk->major = RAMDISK_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &brd_fops;
disk->private_data = brd;
disk->queue = brd->brd_queue;
@@ -523,7 +527,12 @@ static int __init brd_init(void)
* themselves and have kernel automatically instantiate actual
* device on-demand.
*/
- if (rd_nr > 1UL << MINORBITS)
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
+ if (rd_nr > 1UL << (MINORBITS - part_shift))
return -EINVAL;
if (rd_nr) {
@@ -531,7 +540,7 @@ static int __init brd_init(void)
range = rd_nr;
} else {
nr = CONFIG_BLK_DEV_RAM_COUNT;
- range = 1UL << MINORBITS;
+ range = 1UL << (MINORBITS - part_shift);
}
if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
@@ -570,7 +579,7 @@ static void __exit brd_exit(void)
unsigned long range;
struct brd_device *brd, *next;
- range = rd_nr ? rd_nr : 1UL << MINORBITS;
+ range = rd_nr ? rd_nr : 1UL << (MINORBITS - part_shift);
list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
brd_del_one(brd);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 7e31d5f1bc8..e5cd856a2fe 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -143,7 +143,7 @@ restart:
int len;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- len = tty->driver->write(tty, skb->data, skb->len);
+ len = tty->ops->write(tty, skb->data, skb->len);
hdev->stat.byte_tx += len;
skb_pull(skb, len);
@@ -190,8 +190,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
- if (tty->driver && tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
hu->proto->flush(hu);
@@ -285,9 +284,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
-
- if (tty->driver && tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
return 0;
}
@@ -373,9 +370,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static int hci_uart_register_dev(struct hci_uart *hu)
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index c69f79598e4..99e6a406efb 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -35,7 +35,7 @@
//#define AGP_DEBUG 1
#ifdef AGP_DEBUG
-#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __FUNCTION__ , ## y)
+#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __func__ , ## y)
#else
#define DBG(x,y...) do { } while (0)
#endif
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 3d468f502d2..37457e5a4f2 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -832,33 +832,34 @@ static void change_speed(struct async_struct *info,
local_irq_restore(flags);
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct async_struct *info;
unsigned long flags;
if (!tty)
- return;
+ return 0;
info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!info->xmit.buf)
- return;
+ return 0;
local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE) == 0) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit.buf[info->xmit.head++] = ch;
info->xmit.head &= SERIAL_XMIT_SIZE-1;
local_irq_restore(flags);
+ return 1;
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -1074,6 +1075,7 @@ static int get_serial_info(struct async_struct * info,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.type = state->type;
tmp.line = state->line;
tmp.port = state->port;
@@ -1084,6 +1086,7 @@ static int get_serial_info(struct async_struct * info,
tmp.close_delay = state->close_delay;
tmp.closing_wait = state->closing_wait;
tmp.custom_divisor = state->custom_divisor;
+ unlock_kernel();
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -1099,13 +1102,17 @@ static int set_serial_info(struct async_struct * info,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
+
+ lock_kernel();
state = info->state;
old_state = *state;
change_irq = new_serial.irq != state->irq;
change_port = (new_serial.port != state->port);
- if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size))
+ if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
+ unlock_kernel();
return -EINVAL;
+ }
if (!serial_isroot()) {
if ((new_serial.baud_base != state->baud_base) ||
@@ -1122,8 +1129,10 @@ static int set_serial_info(struct async_struct * info,
goto check_and_exit;
}
- if (new_serial.baud_base < 9600)
+ if (new_serial.baud_base < 9600) {
+ unlock_kernel();
return -EINVAL;
+ }
/*
* OK, past this point, all the error checking has been done.
@@ -1157,6 +1166,7 @@ check_and_exit:
}
} else
retval = startup(info);
+ unlock_kernel();
return retval;
}
@@ -1496,8 +1506,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
rs_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1530,6 +1539,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
return; /* Just in case.... */
orig_jiffies = jiffies;
+
+ lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -1570,6 +1581,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
__set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index a7c4990b5b6..31d08b641f5 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -199,7 +199,7 @@ static int __init applicom_init(void)
if (pci_enable_device(dev))
return -EIO;
- RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO);
+ RamIO = ioremap_nocache(pci_resource_start(dev, 0), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
@@ -254,7 +254,7 @@ static int __init applicom_init(void)
/* Now try the specified ISA cards */
for (i = 0; i < MAX_ISA_BOARD; i++) {
- RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
+ RamIO = ioremap_nocache(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1);
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 6b104e45a32..4246b8e36cb 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -277,6 +277,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);
static void update_user_maps(void)
{
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e4f579c3e24..ef73e72daed 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -21,7 +21,6 @@
*
* This version supports shared IRQ's (only for PCI boards).
*
- * $Log: cyclades.c,v $
* Prevent users from opening non-existing Z ports.
*
* Revision 2.3.2.8 2000/07/06 18:14:16 ivan
@@ -62,7 +61,7 @@
* Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
*
* Revision 2.3.2.2 1999/10/01 11:27:43 ivan
- * Fixed bug in cyz_poll that would make all ports but port 0
+ * Fixed bug in cyz_poll that would make all ports but port 0
* unable to transmit/receive data (Cyclades-Z only);
* Implemented logic to prevent the RX buffer from being stuck with data
* due to a driver / firmware race condition in interrupt op mode
@@ -83,25 +82,25 @@
* Revision 2.3.1.1 1999/07/15 16:45:53 ivan
* Removed CY_PROC conditional compilation;
* Implemented SMP-awareness for the driver;
- * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
+ * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
* functions;
* The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
* (irq=NN) as parameters (only for ISA boards);
- * Fixed bug in set_line_char that would prevent the Cyclades-Z
+ * Fixed bug in set_line_char that would prevent the Cyclades-Z
* ports from being configured at speeds above 115.2Kbps;
* Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
* switching from working properly;
- * The driver now only prints IRQ info for the Cyclades-Z if it's
+ * The driver now only prints IRQ info for the Cyclades-Z if it's
* configured to work in interrupt mode;
*
* Revision 2.2.2.3 1999/06/28 11:13:29 ivan
* Added support for interrupt mode operation for the Z cards;
* Removed the driver inactivity control for the Z;
- * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
+ * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
* the Z firmware is not loaded yet;
- * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
+ * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
* same functionality;
- * Implemented workaround for IRQ setting loss on the PCI configuration
+ * Implemented workaround for IRQ setting loss on the PCI configuration
* registers after a PCI bridge EEPROM reload (affects PLX9060 only);
*
* Revision 2.2.2.2 1999/05/14 17:18:15 ivan
@@ -112,22 +111,22 @@
* BREAK implementation changed in order to make use of the 'break_ctl'
* TTY facility;
* Fixed typo in TTY structure field 'driver_name';
- * Included a PCI bridge reset and EEPROM reload in the board
+ * Included a PCI bridge reset and EEPROM reload in the board
* initialization code (for both Y and Z series).
*
* Revision 2.2.2.1 1999/04/08 16:17:43 ivan
- * Fixed a bug in cy_wait_until_sent that was preventing the port to be
+ * Fixed a bug in cy_wait_until_sent that was preventing the port to be
* closed properly after a SIGINT;
* Module usage counter scheme revisited;
* Added support to the upcoming Y PCI boards (i.e., support to additional
* PCI Device ID's).
- *
+ *
* Revision 2.2.1.10 1999/01/20 16:14:29 ivan
* Removed all unnecessary page-alignement operations in ioremap calls
* (ioremap is currently safe for these operations).
*
* Revision 2.2.1.9 1998/12/30 18:18:30 ivan
- * Changed access to PLX PCI bridge registers from I/O to MMIO, in
+ * Changed access to PLX PCI bridge registers from I/O to MMIO, in
* order to make PLX9050-based boards work with certain motherboards.
*
* Revision 2.2.1.8 1998/11/13 12:46:20 ivan
@@ -148,7 +147,7 @@
* Fixed Cyclom-4Yo hardware detection bug.
*
* Revision 2.2.1.4 1998/08/04 11:02:50 ivan
- * /proc/cyclades implementation with great collaboration of
+ * /proc/cyclades implementation with great collaboration of
* Marc Lewis <marc@blarg.net>;
* cyy_interrupt was changed to avoid occurrence of kernel oopses
* during PPP operation.
@@ -157,7 +156,7 @@
* General code review in order to comply with 2.1 kernel standards;
* data loss prevention for slow devices revisited (cy_wait_until_sent
* was created);
- * removed conditional compilation for new/old PCI structure support
+ * removed conditional compilation for new/old PCI structure support
* (now the driver only supports the new PCI structure).
*
* Revision 2.2.1.1 1998/03/19 16:43:12 ivan
@@ -168,7 +167,7 @@
* cleaned up the data loss fix;
* fixed XON/XOFF handling once more (Cyclades-Z);
* general review of the driver routines;
- * introduction of a mechanism to prevent data loss with slow
+ * introduction of a mechanism to prevent data loss with slow
* printers, by forcing a delay before closing the port.
*
* Revision 2.1.1.2 1998/02/17 16:50:00 ivan
@@ -182,12 +181,12 @@
* Code review for the module cleanup routine;
* fixed RTS and DTR status report for new CD1400's in get_modem_info;
* includes anonymous changes regarding signal_pending.
- *
+ *
* Revision 2.1 1997/11/01 17:42:41 ivan
* Changes in the driver to support Alpha systems (except 8Zo V_1);
* BREAK fix for the Cyclades-Z boards;
* driver inactivity control by FW implemented;
- * introduction of flag that allows driver to take advantage of
+ * introduction of flag that allows driver to take advantage of
* a special CD1400 feature related to HW flow control;
* added support for the CD1400 rev. J (Cyclom-Y boards);
* introduction of ioctls to:
@@ -196,17 +195,17 @@
* - adjust the polling interval (Cyclades-Z);
*
* Revision 1.36.4.33 1997/06/27 19:00:00 ivan
- * Fixes related to kernel version conditional
+ * Fixes related to kernel version conditional
* compilation.
- *
+ *
* Revision 1.36.4.32 1997/06/14 19:30:00 ivan
- * Compatibility issues between kernels 2.0.x and
+ * Compatibility issues between kernels 2.0.x and
* 2.1.x (mainly related to clear_bit function).
- *
+ *
* Revision 1.36.4.31 1997/06/03 15:30:00 ivan
- * Changes to define the memory window according to the
+ * Changes to define the memory window according to the
* board type.
- *
+ *
* Revision 1.36.4.30 1997/05/16 15:30:00 daniel
* Changes to support new cycladesZ boards.
*
@@ -624,7 +623,7 @@
#undef CY_PCI_DEBUG
/*
- * Include section
+ * Include section
*/
#include <linux/module.h>
#include <linux/errno.h>
@@ -649,9 +648,9 @@
#include <linux/firmware.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -668,10 +667,10 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
((readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
-#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
+#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
Z_FPGA_CHECK(card)) && \
- (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
+ (ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
((card).base_addr+ID_ADDRESS))->signature)))
#ifndef SERIAL_XMIT_SIZE
@@ -809,12 +808,12 @@ static char baud_cor3[] = { /* receive threshold */
/*
* The Cyclades driver implements HW flow control as any serial driver.
- * The cyclades_port structure member rflow and the vector rflow_thr
- * allows us to take advantage of a special feature in the CD1400 to avoid
- * data loss even when the system interrupt latency is too high. These flags
- * are to be used only with very special applications. Setting these flags
- * requires the use of a special cable (DTR and RTS reversed). In the new
- * CD1400-based boards (rev. 6.00 or later), there is no need for special
+ * The cyclades_port structure member rflow and the vector rflow_thr
+ * allows us to take advantage of a special feature in the CD1400 to avoid
+ * data loss even when the system interrupt latency is too high. These flags
+ * are to be used only with very special applications. Setting these flags
+ * requires the use of a special cable (DTR and RTS reversed). In the new
+ * CD1400-based boards (rev. 6.00 or later), there is no need for special
* cables.
*/
@@ -841,14 +840,22 @@ static int cy_chip_offset[] = { 0x0000,
#ifdef CONFIG_PCI
static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, /* PCI > 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, /* 4Y PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, /* 4Y PCI > 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, /* 8Y PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, /* 8Y PCI > 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, /* Z PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, /* Z PCI > 1Mb */
+ /* PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
+ /* PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
+ /* 4Y PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
+ /* 4Y PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
+ /* 8Y PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
+ /* 8Y PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
+ /* Z PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
+ /* Z PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
{ } /* end of table */
};
MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
@@ -905,15 +912,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
This function is only called from inside spinlock-protected code.
*/
-static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
+static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
{
unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (readb(base_addr + (CyCCR << index)) == 0) {
+ if (readb(base_addr + (CyCCR << index)) == 0)
break;
- }
udelay(10L);
}
/* if the CCR never cleared, the previous command
@@ -929,7 +935,7 @@ static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
-static unsigned detect_isa_irq(void __iomem * address)
+static unsigned detect_isa_irq(void __iomem *address)
{
int irq;
unsigned long irqs, flags;
@@ -1038,7 +1044,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (data & CyFRAME) {
- tty_insert_flip_char( tty,
+ tty_insert_flip_char(tty,
readb(base_addr + (CyRDSR <<
index)), TTY_FRAME);
info->icount.rx++;
@@ -1320,7 +1326,8 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
+ printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
+ irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1375,12 +1382,12 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
-/******** Start of block of Cyclades-Z specific code *********/
+/******** Start of block of Cyclades-Z specific code *******/
/***********************************************************/
static int
cyz_fetch_msg(struct cyclades_card *cinfo,
- __u32 * channel, __u8 * cmd, __u32 * param)
+ __u32 *channel, __u8 *cmd, __u32 *param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -1388,9 +1395,8 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
unsigned long loc_doorbell;
firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo))
return -1;
- }
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@@ -1418,9 +1424,9 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
unsigned int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo))
return -1;
- }
+
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@@ -1428,9 +1434,8 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
pci_doorbell =
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
while ((readl(pci_doorbell) & 0xff) != 0) {
- if (index++ == 1000) {
+ if (index++ == 1000)
return (int)(readl(pci_doorbell) & 0xff);
- }
udelay(50L);
}
cy_writel(&board_ctrl->hcmd_channel, channel);
@@ -1504,7 +1509,8 @@ static void cyz_handle_rx(struct cyclades_port *info,
while (len--) {
data = readb(cinfo->base_addr + rx_bufaddr +
new_rx_get);
- new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
+ new_rx_get = (new_rx_get + 1) &
+ (rx_bufsize - 1);
tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
@@ -1636,7 +1642,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
special_count = 0;
delta_count = 0;
info = &cinfo->ports[channel];
- if ((tty = info->tty) == NULL)
+ tty = info->tty;
+ if (tty == NULL)
continue;
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
@@ -1732,7 +1739,8 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
+ printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
+ irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1851,9 +1859,8 @@ static int startup(struct cyclades_port *info)
}
if (!info->type) {
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
free_page(page);
goto errout;
}
@@ -1904,9 +1911,8 @@ static int startup(struct cyclades_port *info)
readb(base_addr + (CySRER << index)) | CyRxData);
info->flags |= ASYNC_INITIALIZED;
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
info->breakon = info->breakoff = 0;
memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -1925,9 +1931,8 @@ static int startup(struct cyclades_port *info)
base_addr = card->base_addr;
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return -ENODEV;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -1990,9 +1995,8 @@ static int startup(struct cyclades_port *info)
/* enable send, recv, modem !!! */
info->flags |= ASYNC_INITIALIZED;
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
info->breakon = info->breakoff = 0;
memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -2061,9 +2065,8 @@ static void shutdown(struct cyclades_port *info)
void __iomem *base_addr;
int chip, channel, index;
- if (!(info->flags & ASYNC_INITIALIZED)) {
+ if (!(info->flags & ASYNC_INITIALIZED))
return;
- }
card = info->card;
channel = info->line - card->first_line;
@@ -2105,9 +2108,8 @@ static void shutdown(struct cyclades_port *info)
/* it may be appropriate to clear _XMIT at
some later date (after testing)!!! */
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
@@ -2124,9 +2126,8 @@ static void shutdown(struct cyclades_port *info)
#endif
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -2157,9 +2158,8 @@ static void shutdown(struct cyclades_port *info)
#endif
}
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2204,7 +2204,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
* If non-blocking mode is set, then make the check up front
* and then exit.
*/
- if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -2301,7 +2302,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
return -EINVAL;
}
- zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
+ zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)
+ & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
@@ -2378,9 +2380,9 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
int retval;
line = tty->index;
- if ((tty->index < 0) || (NR_PORTS <= line)) {
+ if (tty->index < 0 || NR_PORTS <= line)
return -ENODEV;
- }
+
for (i = 0; i < NR_CARDS; i++)
if (line < cy_card[i].first_line + cy_card[i].nports &&
line >= cy_card[i].first_line)
@@ -2388,9 +2390,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
if (i >= NR_CARDS)
return -ENODEV;
info = &cy_card[i].ports[line - cy_card[i].first_line];
- if (info->line < 0) {
+ if (info->line < 0)
return -ENODEV;
- }
/* If the card's firmware hasn't been loaded,
treat it as absent from the system. This
@@ -2456,9 +2457,9 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
#endif
tty->driver_data = info;
info->tty = tty;
- if (serial_paranoia_check(info, tty->name, "cy_open")) {
+ if (serial_paranoia_check(info, tty->name, "cy_open"))
return -ENODEV;
- }
+
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
info->count);
@@ -2482,9 +2483,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* Start up serial port
*/
retval = startup(info);
- if (retval) {
+ if (retval)
return retval;
- }
retval = block_til_ready(tty, filp, info);
if (retval) {
@@ -2522,6 +2522,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
return; /* Just in case.... */
orig_jiffies = jiffies;
+ lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -2573,11 +2574,47 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
+ unlock_kernel();
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
#endif
}
+static void cy_flush_buffer(struct tty_struct *tty)
+{
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel, retval;
+ unsigned long flags;
+
+#ifdef CY_DEBUG_IO
+ printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
+#endif
+
+ if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
+ return;
+
+ card = info->card;
+ channel = info->line - card->first_line;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ spin_unlock_irqrestore(&card->card_lock, flags);
+
+ if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
+ buffers as well */
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
+ if (retval != 0) {
+ printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ }
+ tty_wakeup(tty);
+} /* cy_flush_buffer */
+
+
/*
* This routine is called when a particular tty device is closed.
*/
@@ -2591,9 +2628,8 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
#endif
- if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
return;
- }
card = info->card;
@@ -2641,9 +2677,9 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
*/
tty->closing = 1;
spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->closing_wait);
- }
+
spin_lock_irqsave(&card->card_lock, flags);
if (!IS_CYC_Z(*card)) {
@@ -2657,15 +2693,16 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) & ~CyRxData);
if (info->flags & ASYNC_INITIALIZED) {
- /* Waiting for on-board buffers to be empty before closing
- the port */
+ /* Waiting for on-board buffers to be empty before
+ closing the port */
spin_unlock_irqrestore(&card->card_lock, flags);
cy_wait_until_sent(tty, info->timeout);
spin_lock_irqsave(&card->card_lock, flags);
}
} else {
#ifdef Z_WAKE
- /* Waiting for on-board buffers to be empty before closing the port */
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
void __iomem *base_addr = card->base_addr;
struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl =
@@ -2689,8 +2726,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
spin_unlock_irqrestore(&card->card_lock, flags);
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ cy_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
@@ -2738,17 +2774,16 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write")) {
+ if (serial_paranoia_check(info, tty->name, "cy_write"))
return 0;
- }
if (!info->xmit_buf)
return 0;
spin_lock_irqsave(&info->card->card_lock, flags);
while (1) {
- c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
- (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
+ c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
+ c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
@@ -2766,9 +2801,9 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
start_xmit(info);
- }
+
return ret;
} /* cy_write */
@@ -2779,7 +2814,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
* done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored.
*/
-static void cy_put_char(struct tty_struct *tty, unsigned char ch)
+static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
@@ -2789,15 +2824,15 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->card->card_lock, flags);
if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
spin_unlock_irqrestore(&info->card->card_lock, flags);
- return;
+ return 0;
}
info->xmit_buf[info->xmit_head++] = ch;
@@ -2806,11 +2841,12 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
spin_unlock_irqrestore(&info->card->card_lock, flags);
+ return 1;
} /* cy_put_char */
/*
* This routine is called by the kernel after it has written a
- * series of characters to the tty device using put_char().
+ * series of characters to the tty device using put_char().
*/
static void cy_flush_chars(struct tty_struct *tty)
{
@@ -2882,6 +2918,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
int char_count;
__u32 tx_put, tx_get, tx_bufsize;
+ lock_kernel();
firm_id = card->base_addr + ID_ADDRESS;
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -2899,6 +2936,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt + char_count);
#endif
+ unlock_kernel();
return info->xmit_cnt + char_count;
}
#endif /* Z_EXT_CHARS_IN_BUFFER */
@@ -2950,12 +2988,12 @@ static void set_line_char(struct cyclades_port *info)
int baud, baud_rate = 0;
int i;
- if (!info->tty || !info->tty->termios) {
+ if (!info->tty || !info->tty->termios)
return;
- }
- if (info->line == -1) {
+
+ if (info->line == -1)
return;
- }
+
cflag = info->tty->termios->c_cflag;
iflag = info->tty->termios->c_iflag;
@@ -2994,13 +3032,11 @@ static void set_line_char(struct cyclades_port *info)
}
/* find the baud index */
for (i = 0; i < 20; i++) {
- if (baud == baud_table[i]) {
+ if (baud == baud_table[i])
break;
- }
}
- if (i == 20) {
+ if (i == 20)
i = 19; /* CD1400_MAX_SPEED */
- }
if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
@@ -3059,18 +3095,16 @@ static void set_line_char(struct cyclades_port *info)
info->cor1 = Cy_8_BITS;
break;
}
- if (cflag & CSTOPB) {
+ if (cflag & CSTOPB)
info->cor1 |= Cy_2_STOP;
- }
+
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & PARODD)
info->cor1 |= CyPARITY_O;
- } else {
+ else
info->cor1 |= CyPARITY_E;
- }
- } else {
+ } else
info->cor1 |= CyPARITY_NONE;
- }
/* CTS flow control flag */
if (cflag & CRTSCTS) {
@@ -3123,7 +3157,8 @@ static void set_line_char(struct cyclades_port *info)
cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
CyCOR3ch, index);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
+ /* !!! Is this needed? */
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
cy_writeb(base_addr + (CyRTPR << index),
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
@@ -3191,9 +3226,8 @@ static void set_line_char(struct cyclades_port *info)
#endif
}
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
@@ -3206,9 +3240,8 @@ static void set_line_char(struct cyclades_port *info)
int retval;
firm_id = card->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -3268,14 +3301,12 @@ static void set_line_char(struct cyclades_port *info)
readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
}
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & PARODD)
cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
- } else {
+ else
cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
- }
- } else {
+ } else
cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
- }
/* CTS flow control flag */
if (cflag & CRTSCTS) {
@@ -3305,11 +3336,10 @@ static void set_line_char(struct cyclades_port *info)
}
/* CD sensitivity */
- if (cflag & CLOCAL) {
+ if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
- } else {
+ else
info->flags |= ASYNC_CHECK_CD;
- }
if (baud == 0) { /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
@@ -3325,21 +3355,20 @@ static void set_line_char(struct cyclades_port *info)
#endif
}
- retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
"was %x\n", info->line, retval);
}
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
}
} /* set_line_char */
static int
get_serial_info(struct cyclades_port *info,
- struct serial_struct __user * retinfo)
+ struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
struct cyclades_card *cinfo = info->card;
@@ -3363,7 +3392,7 @@ get_serial_info(struct cyclades_port *info,
static int
set_serial_info(struct cyclades_port *info,
- struct serial_struct __user * new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
struct cyclades_port old_info;
@@ -3417,7 +3446,7 @@ check_and_exit:
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
+static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
{
struct cyclades_card *card;
int chip, channel, index;
@@ -3461,9 +3490,11 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
+ lock_kernel();
+
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
@@ -3506,10 +3537,12 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
} else {
result = 0;
+ unlock_kernel();
return -ENODEV;
}
}
+ unlock_kernel();
return result;
} /* cy_tiomget */
@@ -3528,7 +3561,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
card = info->card;
@@ -3727,8 +3760,8 @@ static void cy_break(struct tty_struct *tty, int break_state)
spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_break */
-static int
-get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
+static int get_mon_info(struct cyclades_port *info,
+ struct cyclades_monitor __user *mon)
{
if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
@@ -3767,8 +3800,8 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
return 0;
} /* set_threshold */
-static int
-get_threshold(struct cyclades_port *info, unsigned long __user * value)
+static int get_threshold(struct cyclades_port *info,
+ unsigned long __user *value)
{
struct cyclades_card *card;
void __iomem *base_addr;
@@ -3789,15 +3822,15 @@ get_threshold(struct cyclades_port *info, unsigned long __user * value)
return 0;
} /* get_threshold */
-static int
-set_default_threshold(struct cyclades_port *info, unsigned long value)
+static int set_default_threshold(struct cyclades_port *info,
+ unsigned long value)
{
info->default_threshold = value & 0x0f;
return 0;
} /* set_default_threshold */
-static int
-get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
+static int get_default_threshold(struct cyclades_port *info,
+ unsigned long __user *value)
{
return put_user(info->default_threshold, value);
} /* get_default_threshold */
@@ -3824,7 +3857,8 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
return 0;
} /* set_timeout */
-static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
+static int get_timeout(struct cyclades_port *info,
+ unsigned long __user *value)
{
struct cyclades_card *card;
void __iomem *base_addr;
@@ -3851,8 +3885,8 @@ static int set_default_timeout(struct cyclades_port *info, unsigned long value)
return 0;
} /* set_default_timeout */
-static int
-get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
+static int get_default_timeout(struct cyclades_port *info,
+ unsigned long __user *value)
{
return put_user(info->default_timeout, value);
} /* get_default_timeout */
@@ -3880,6 +3914,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
info->line, cmd, arg);
#endif
+ lock_kernel();
switch (cmd) {
case CYGETMON:
@@ -3936,7 +3971,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
break;
#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
- info->closing_wait = (unsigned short)arg *HZ / 100;
+ info->closing_wait = (unsigned short)arg * HZ / 100;
ret_val = 0;
break;
case CYGETWAIT:
@@ -3988,47 +4023,47 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
p_cuser = argp;
ret_val = put_user(cnow.cts, &p_cuser->cts);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.dsr, &p_cuser->dsr);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.rng, &p_cuser->rng);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.dcd, &p_cuser->dcd);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.rx, &p_cuser->rx);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.tx, &p_cuser->tx);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.frame, &p_cuser->frame);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.overrun, &p_cuser->overrun);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.parity, &p_cuser->parity);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.brk, &p_cuser->brk);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
if (ret_val)
- return ret_val;
+ break;
ret_val = 0;
break;
default:
ret_val = -ENOIOCTLCMD;
}
+ unlock_kernel();
#ifdef CY_DEBUG_OTHER
printk(KERN_DEBUG "cyc:cy_ioctl done\n");
#endif
-
return ret_val;
} /* cy_ioctl */
@@ -4113,9 +4148,8 @@ static void cy_throttle(struct tty_struct *tty)
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
+ if (serial_paranoia_check(info, tty->name, "cy_throttle"))
return;
- }
card = info->card;
@@ -4169,12 +4203,11 @@ static void cy_unthrottle(struct tty_struct *tty)
char buf[64];
printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
- tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
+ tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
+ if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
return;
- }
if (I_IXOFF(tty)) {
if (info->x_char)
@@ -4269,47 +4302,14 @@ static void cy_start(struct tty_struct *tty)
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) (channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) | CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
-static void cy_flush_buffer(struct tty_struct *tty)
-{
- struct cyclades_port *info = tty->driver_data;
- struct cyclades_card *card;
- int channel, retval;
- unsigned long flags;
-
-#ifdef CY_DEBUG_IO
- printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
-#endif
-
- if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
- return;
-
- card = info->card;
- channel = info->line - card->first_line;
-
- spin_lock_irqsave(&card->card_lock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irqrestore(&card->card_lock, flags);
-
- if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
- buffers as well */
- spin_lock_irqsave(&card->card_lock, flags);
- retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
- "was %x\n", info->line, retval);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- tty_wakeup(tty);
-} /* cy_flush_buffer */
-
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
@@ -4406,10 +4406,11 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
info->cor3 = 0x08; /* _very_ small rcv threshold */
chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev = readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] <<
- index) + (CyGFRCR << index))) >=
- CD1400_REV_J) {
+ info->chip_rev = readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] << index) +
+ (CyGFRCR << index));
+
+ if (info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[13]; /* Tx BPR */
info->tco = baud_co_60[13]; /* Tx CO */
@@ -4454,7 +4455,8 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
/* Cy_ClrIntr is 0x1800 */
udelay(500L);
- for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
+ for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
+ chip_number++) {
base_addr =
true_base_addr + (cy_chip_offset[chip_number] << index);
mdelay(1);
@@ -4555,12 +4557,11 @@ static int __init cy_detect_isa(void)
/* scan the address table probing for Cyclom-Y/ISA boards */
for (i = 0; i < NR_ISA_ADDRS; i++) {
unsigned int isa_address = cy_isa_addresses[i];
- if (isa_address == 0x0000) {
+ if (isa_address == 0x0000)
return nboard;
- }
/* probe for CD1400... */
- cy_isa_address = ioremap(isa_address, CyISA_Ywin);
+ cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
if (cy_isa_address == NULL) {
printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
"address\n");
@@ -4847,12 +4848,10 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
if (mailbox != 0) {
/* set window to last 512K of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
- //sleep(1);
for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
cy_writeb(tmp, 255);
/* set window to beginning of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
- //sleep(1);
}
retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
@@ -5382,7 +5381,8 @@ static void __exit cy_cleanup_module(void)
del_timer_sync(&cyz_timerlist);
#endif /* CONFIG_CYZ_INTR */
- if ((e1 = tty_unregister_driver(cy_serial_driver)))
+ e1 = tty_unregister_driver(cy_serial_driver);
+ if (e1)
printk(KERN_ERR "failed to unregister Cyclades serial "
"driver(%d)\n", e1);
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index ecee3547a13..213b3ca3468 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -160,7 +160,7 @@ struct drm_device;
* \param arg arguments
*/
#define DRM_ERROR(fmt, arg...) \
- printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg)
+ printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg)
/**
* Memory error output.
@@ -170,7 +170,7 @@ struct drm_device;
* \param arg arguments
*/
#define DRM_MEM_ERROR(area, fmt, arg...) \
- printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \
+ printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \
drm_mem_stats[area].name , ##arg)
#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
@@ -187,7 +187,7 @@ struct drm_device;
if ( drm_debug ) \
printk(KERN_DEBUG \
"[" DRM_NAME ":%s] " fmt , \
- __FUNCTION__ , ##arg); \
+ __func__ , ##arg); \
} while (0)
#else
#define DRM_DEBUG(fmt, arg...) do { } while (0)
@@ -238,7 +238,7 @@ do { \
if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \
dev->lock.file_priv != file_priv ) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
- __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
+ __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
dev->lock.file_priv, file_priv ); \
return -EINVAL; \
} \
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 7a1d9a782dd..9a32169e88f 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -34,7 +34,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev;
- printk(KERN_ERR "%s\n", __FUNCTION__);
+ printk(KERN_ERR "%s\n", __func__);
if (drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev, state);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 60c9376be48..a86ab30b462 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -692,7 +692,7 @@ static void i830EmitState(struct drm_device * dev)
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
- DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
+ DRM_DEBUG("%s %x\n", __func__, dirty);
if (dirty & I830_UPLOAD_BUFFERS) {
i830EmitDestVerified(dev, sarea_priv->BufferState);
@@ -1043,7 +1043,7 @@ static void i830_dma_dispatch_flip(struct drm_device * dev)
RING_LOCALS;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
+ __func__,
dev_priv->current_page,
dev_priv->sarea_priv->pf_current_page);
@@ -1206,7 +1206,7 @@ static void i830_dma_quiescent(struct drm_device * dev)
OUT_RING(0);
ADVANCE_LP_RING();
- i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
static int i830_flush_queue(struct drm_device * dev)
@@ -1223,7 +1223,7 @@ static int i830_flush_queue(struct drm_device * dev)
OUT_RING(0);
ADVANCE_LP_RING();
- i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
for (i = 0; i < dma->buf_count; i++) {
struct drm_buf *buf = dma->buflist[i];
@@ -1344,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
dev_priv->page_flipping = 1;
dev_priv->current_page = 0;
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
@@ -1354,7 +1354,7 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (dev_priv->current_page != 0)
i830_dma_dispatch_flip(dev);
@@ -1367,7 +1367,7 @@ static int i830_flip_bufs(struct drm_device *dev, void *data,
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1437,7 +1437,7 @@ static int i830_getparam(struct drm_device *dev, void *data,
int value;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -1464,7 +1464,7 @@ static int i830_setparam(struct drm_device *dev, void *data,
drm_i830_setparam_t *param = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 4caba8c5445..b5bf8cc0fda 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -158,7 +158,7 @@ extern int i830_driver_device_is_agp(struct drm_device * dev);
if (I830_VERBOSE) \
printk("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < n*4) \
- i830_wait_ring(dev, n*4, __FUNCTION__); \
+ i830_wait_ring(dev, n*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index a33db5f0967..91ec2bb497e 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -58,7 +58,7 @@ static int i830_emit_irq(struct drm_device * dev)
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
atomic_inc(&dev_priv->irq_emitted);
@@ -77,7 +77,7 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr)
unsigned long end = jiffies + HZ * 3;
int ret = 0;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
return 0;
@@ -124,7 +124,7 @@ int i830_irq_emit(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -147,7 +147,7 @@ int i830_irq_wait(struct drm_device *dev, void *data,
drm_i830_irq_wait_t *irqwait = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index ef7bf143a80..f47e46e3529 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -194,7 +194,7 @@ static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
@@ -609,7 +609,7 @@ static int i915_quiescent(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index c614d78b3df..db7001f2256 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -272,7 +272,7 @@ extern void i915_mem_release(struct drm_device * dev,
if (I915_VERBOSE) \
DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < (n)*4) \
- i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ i915_wait_ring(dev, (n)*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 9072e4a1894..f6f6c92bf77 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -894,7 +894,7 @@ static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
#if RADEON_FIFO_DEBUG
static void radeon_status(drm_radeon_private_t * dev_priv)
{
- printk("%s:\n", __FUNCTION__);
+ printk("%s:\n", __func__);
printk("RBBM_STATUS = 0x%08x\n",
(unsigned int)RADEON_READ(RADEON_RBBM_STATUS));
printk("CP_RB_RTPR = 0x%08x\n",
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index 59146e3365b..ea35ab2c990 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -39,6 +39,7 @@
#include <linux/spinlock.h>
#include <linux/bcd.h>
#include <linux/proc_fs.h>
+#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -451,7 +452,7 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
*/
if (ds1286_is_updating() != 0)
- while (jiffies - uip_watchdog < 2*HZ/100)
+ while (time_before(jiffies, uip_watchdog + 2*HZ/100))
barrier();
/*
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index ffd747c5dff..60a4df7dac1 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -38,8 +38,8 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include "digiPCI.h"
@@ -73,7 +73,8 @@ static int invalid_lilo_config;
*/
static DEFINE_SPINLOCK(epca_lock);
-/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */
+/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
+ to 7 below. */
static struct board_info boards[MAXBOARDS];
static struct tty_driver *pc_driver;
@@ -157,13 +158,12 @@ static void epca_error(int, char *);
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
static void pc_hangup(struct tty_struct *);
-static void pc_put_char(struct tty_struct *, unsigned char);
static int pc_write_room(struct tty_struct *);
static int pc_chars_in_buffer(struct tty_struct *);
static void pc_flush_buffer(struct tty_struct *);
static void pc_flush_chars(struct tty_struct *);
static int block_til_ready(struct tty_struct *, struct file *,
- struct channel *);
+ struct channel *);
static int pc_open(struct tty_struct *, struct file *);
static void post_fep_init(unsigned int crd);
static void epcapoll(unsigned long);
@@ -175,18 +175,18 @@ static unsigned termios2digi_c(struct channel *ch, unsigned);
static void epcaparam(struct tty_struct *, struct channel *);
static void receive_data(struct channel *);
static int pc_ioctl(struct tty_struct *, struct file *,
- unsigned int, unsigned long);
+ unsigned int, unsigned long);
static int info_ioctl(struct tty_struct *, struct file *,
- unsigned int, unsigned long);
+ unsigned int, unsigned long);
static void pc_set_termios(struct tty_struct *, struct ktermios *);
static void do_softint(struct work_struct *work);
static void pc_stop(struct tty_struct *);
static void pc_start(struct tty_struct *);
-static void pc_throttle(struct tty_struct * tty);
+static void pc_throttle(struct tty_struct *tty);
static void pc_unthrottle(struct tty_struct *tty);
static void digi_send_break(struct channel *ch, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
-void epca_setup(char *, int *);
+static void epca_setup(char *, int *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void);
@@ -243,7 +243,7 @@ static void assertmemoff(struct channel *ch)
/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN|win, b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
static void pcxem_memwinoff(struct board_info *b, unsigned int win)
@@ -253,7 +253,7 @@ static void pcxem_memwinoff(struct board_info *b, unsigned int win)
static void pcxem_globalwinon(struct channel *ch)
{
- outb_p( FEPWIN, (int)ch->board->port + 1);
+ outb_p(FEPWIN, (int)ch->board->port + 1);
}
static void pcxem_rxwinon(struct channel *ch)
@@ -394,7 +394,7 @@ static struct channel *verifyChannel(struct tty_struct *tty)
*/
if (tty) {
struct channel *ch = (struct channel *)tty->driver_data;
- if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
+ if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
if (ch->magic == EPCA_MAGIC)
return ch;
}
@@ -414,7 +414,7 @@ static void pc_sched_event(struct channel *ch, int event)
static void epca_error(int line, char *msg)
{
- printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
+ printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
}
static void pc_close(struct tty_struct *tty, struct file *filp)
@@ -425,7 +425,8 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&epca_lock, flags);
@@ -440,7 +441,6 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
spin_unlock_irqrestore(&epca_lock, flags);
return;
}
-
/* Port open only once go ahead with shutdown & reset */
BUG_ON(ch->count < 0);
@@ -455,12 +455,13 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
spin_unlock_irqrestore(&epca_lock, flags);
if (ch->asyncflags & ASYNC_INITIALIZED) {
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the
+ transmit buffer empties */
setup_empty_event(tty, ch);
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ /* 30 seconds timeout */
+ tty_wait_until_sent(tty, 3000);
}
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
@@ -477,7 +478,7 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&ch->open_wait);
}
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
- ASYNC_CLOSING);
+ ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
}
}
@@ -524,16 +525,15 @@ static void shutdown(struct channel *ch)
static void pc_hangup(struct tty_struct *tty)
{
struct channel *ch;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
@@ -548,7 +548,7 @@ static void pc_hangup(struct tty_struct *tty)
}
static int pc_write(struct tty_struct *tty,
- const unsigned char *buf, int bytesAvailable)
+ const unsigned char *buf, int bytesAvailable)
{
unsigned int head, tail;
int dataLen;
@@ -572,7 +572,8 @@ static int pc_write(struct tty_struct *tty,
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return 0;
/* Make a pointer to the channel data structure found on the board. */
@@ -645,26 +646,19 @@ static int pc_write(struct tty_struct *tty,
return amountCopied;
}
-static void pc_put_char(struct tty_struct *tty, unsigned char c)
-{
- pc_write(tty, &c, 1);
-}
-
static int pc_write_room(struct tty_struct *tty)
{
- int remain;
+ int remain = 0;
struct channel *ch;
unsigned long flags;
unsigned int head, tail;
struct board_chan __iomem *bc;
-
- remain = 0;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
@@ -676,8 +670,8 @@ static int pc_write_room(struct tty_struct *tty)
tail = readw(&bc->tout);
/* Wrap tail if necessary */
tail &= (ch->txbufsize - 1);
-
- if ((remain = tail - head - 1) < 0 )
+ remain = tail - head - 1;
+ if (remain < 0)
remain += ch->txbufsize;
if (remain && (ch->statusflags & LOWWAIT) == 0) {
@@ -699,12 +693,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
struct channel *ch;
struct board_chan __iomem *bc;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return 0;
spin_lock_irqsave(&epca_lock, flags);
@@ -715,7 +709,8 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
head = readw(&bc->tin);
ctail = readw(&ch->mailbox->cout);
- if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
+ if (tail == head && readw(&ch->mailbox->cin) == ctail &&
+ readb(&bc->tbusy) == 0)
chars = 0;
else { /* Begin if some space on the card has been used */
head = readw(&bc->tin) & (ch->txbufsize - 1);
@@ -725,7 +720,8 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
* pc_write_room here we are finding the amount of bytes in the
* buffer filled. Not the amount of bytes empty.
*/
- if ((remain = tail - head - 1) < 0 )
+ remain = tail - head - 1;
+ if (remain < 0)
remain += ch->txbufsize;
chars = (int)(ch->txbufsize - remain);
/*
@@ -736,7 +732,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
* transmit buffer empties.
*/
if (!(ch->statusflags & EMPTYWAIT))
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
} /* End if some space on the card has been used */
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -754,7 +750,8 @@ static void pc_flush_buffer(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return;
spin_lock_irqsave(&epca_lock, flags);
@@ -775,23 +772,25 @@ static void pc_flush_chars(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
/*
* If not already set and the transmitter is busy setup an
* event to indicate when the transmit empties.
*/
- if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
- setup_empty_event(tty,ch);
+ if ((ch->statusflags & TXBUSY) &&
+ !(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
}
}
static int block_til_ready(struct tty_struct *tty,
- struct file *filp, struct channel *ch)
+ struct file *filp, struct channel *ch)
{
- DECLARE_WAITQUEUE(wait,current);
+ DECLARE_WAITQUEUE(wait, current);
int retval, do_clocal = 0;
unsigned long flags;
@@ -839,8 +838,7 @@ static int block_til_ready(struct tty_struct *tty,
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED))
- {
+ !(ch->asyncflags & ASYNC_INITIALIZED)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
@@ -880,7 +878,7 @@ static int block_til_ready(struct tty_struct *tty,
return 0;
}
-static int pc_open(struct tty_struct *tty, struct file * filp)
+static int pc_open(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
unsigned long flags;
@@ -923,7 +921,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
return(-ENODEV);
}
- if ((bc = ch->brdchan) == 0) {
+ bc = ch->brdchan;
+ if (bc == NULL) {
tty->driver_data = NULL;
return -ENODEV;
}
@@ -964,7 +963,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -1002,8 +1001,8 @@ static void __exit epca_module_exit(void)
del_timer_sync(&epca_timer);
- if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))
- {
+ if (tty_unregister_driver(pc_driver) ||
+ tty_unregister_driver(pc_info)) {
printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
}
@@ -1034,7 +1033,6 @@ static const struct tty_operations pc_ops = {
.flush_buffer = pc_flush_buffer,
.chars_in_buffer = pc_chars_in_buffer,
.flush_chars = pc_flush_chars,
- .put_char = pc_put_char,
.ioctl = pc_ioctl,
.set_termios = pc_set_termios,
.stop = pc_stop,
@@ -1044,7 +1042,7 @@ static const struct tty_operations pc_ops = {
.hangup = pc_hangup,
};
-static int info_open(struct tty_struct *tty, struct file * filp)
+static int info_open(struct tty_struct *tty, struct file *filp)
{
return 0;
}
@@ -1099,7 +1097,7 @@ static int __init pc_init(void)
* Set up interrupt, we will worry about memory allocation in
* post_fep_init.
*/
- printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
+ printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
/*
* NOTE : This code assumes that the number of ports found in the
@@ -1252,7 +1250,7 @@ static int __init pc_init(void)
if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000;
} else
- printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n", (int)bd->port);
break;
}
}
@@ -1326,12 +1324,12 @@ static void post_fep_init(unsigned int crd)
*/
/* PCI cards are already remapped at this point ISA are not */
bd->numports = readw(bd->re_map_membase + XEMPORTS);
- epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+ epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
nbdevs += (bd->numports);
} else {
/* Fix up the mappings for ISA/EISA etc */
/* FIXME: 64K - can we be smarter ? */
- bd->re_map_membase = ioremap(bd->membase, 0x10000);
+ bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
}
if (crd != 0)
@@ -1362,7 +1360,8 @@ static void post_fep_init(unsigned int crd)
* XEPORTS (address 0xc22) points at the number of channels the card
* supports. (For 64XE, XI, XEM, and XR use 0xc02)
*/
- if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
+ if ((bd->type == PCXEVE || bd->type == PCXE) &&
+ (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1;
if (bd->type < PCIXEM)
if (!request_region((int)bd->port, 4, board_desc[bd->type]))
@@ -1461,10 +1460,12 @@ static void post_fep_init(unsigned int crd)
case PCXEVE:
case PCXE:
- ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
+ & 0x1fff);
ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
- ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
- ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
+ ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
+ & 0x1fff);
+ ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
break;
case PCXI:
@@ -1518,8 +1519,9 @@ static void post_fep_init(unsigned int crd)
}
printk(KERN_INFO
- "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
- VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ VERSION, board_desc[bd->type], (long)bd->port,
+ (long)bd->membase, bd->numports);
memwinoff(bd, 0);
}
@@ -1527,7 +1529,7 @@ static void epcapoll(unsigned long ignored)
{
unsigned long flags;
int crd;
- volatile unsigned int head, tail;
+ unsigned int head, tail;
struct channel *ch;
struct board_info *bd;
@@ -1593,7 +1595,9 @@ static void doevent(int crd)
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
assertgwinon(chan0);
- while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */
+ while ((tail = readw(&chan0->mailbox->eout)) !=
+ (head = readw(&chan0->mailbox->ein))) {
+ /* Begin while something in event queue */
assertgwinon(chan0);
eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
@@ -1617,7 +1621,8 @@ static void doevent(int crd)
goto next;
}
- if ((bc = ch->brdchan) == NULL)
+ bc = ch->brdchan;
+ if (bc == NULL)
goto next;
if (event & DATA_IND) { /* Begin DATA_IND */
@@ -1629,10 +1634,11 @@ static void doevent(int crd)
/* A modem signal change has been indicated */
ch->imodem = mstat;
if (ch->asyncflags & ASYNC_CHECK_CD) {
- if (mstat & ch->dcd) /* We are now receiving dcd */
+ /* We are now receiving dcd */
+ if (mstat & ch->dcd)
wake_up_interruptible(&ch->open_wait);
- else
- pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
+ else /* No dcd; hangup */
+ pc_sched_event(ch, EPCA_EVENT_HANGUP);
}
}
tty = ch->tty;
@@ -1647,7 +1653,8 @@ static void doevent(int crd)
tty_wakeup(tty);
}
} else if (event & EMPTYTX_IND) {
- /* This event is generated by setup_empty_event */
+ /* This event is generated by
+ setup_empty_event */
ch->statusflags &= ~TXBUSY;
if (ch->statusflags & EMPTYWAIT) {
ch->statusflags &= ~EMPTYWAIT;
@@ -1655,7 +1662,7 @@ static void doevent(int crd)
}
}
}
- next:
+next:
globalwinon(ch);
BUG_ON(!bc);
writew(1, &bc->idata);
@@ -1665,7 +1672,7 @@ static void doevent(int crd)
}
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
- int byte2, int ncmds, int bytecmd)
+ int byte2, int ncmds, int bytecmd)
{
unchar __iomem *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
@@ -1690,8 +1697,10 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
memaddr = ch->board->re_map_membase;
if (head >= (cmdMax - cmdStart) || (head & 03)) {
- printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head);
- printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart);
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
+ __LINE__, cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
+ __LINE__, cmdMax, cmdStart);
return;
}
if (bytecmd) {
@@ -1770,7 +1779,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
{
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
- INPCK | ISTRIP|IXON|IXANY|IXOFF);
+ INPCK | ISTRIP | IXON | IXANY | IXOFF);
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
@@ -1838,7 +1847,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
unsigned mval, hflow, cflag, iflag;
bc = ch->brdchan;
- epcaassert(bc !=0, "bc out of range");
+ epcaassert(bc != NULL, "bc out of range");
assertgwinon(ch);
ts = tty->termios;
@@ -1884,8 +1893,10 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* Command sets channels iflag structure on the board. Such
* things as input soft flow control, handling of parity
* errors, and break handling are all set here.
+ *
+ * break handling, parity handling, input stripping,
+ * flow control chars
*/
- /* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
/*
@@ -1981,7 +1992,7 @@ static void receive_data(struct channel *ch)
return;
/* If CREAD bit is off or device not open, set TX tail to head */
- if (!tty || !ts || !(ts->c_cflag & CREAD)) {
+ if (!tty || !ts || !(ts->c_cflag & CREAD)) {
writew(head, &bc->rout);
return;
}
@@ -1991,18 +2002,21 @@ static void receive_data(struct channel *ch)
if (readb(&bc->orun)) {
writeb(0, &bc->orun);
- printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
+ printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
+ tty->name);
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
rxwinon(ch);
- while (bytesAvailable > 0) { /* Begin while there is data on the card */
+ while (bytesAvailable > 0) {
+ /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
/*
* Even if head has wrapped around only report the amount of
* data to be equal to the size - tail. Remember memcpy can't
* automaticly wrap around the receive buffer.
*/
- dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
+ dataToRead = (wrapgap < bytesAvailable) ? wrapgap
+ : bytesAvailable;
/* Make sure we don't overflow the buffer */
dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
if (dataToRead == 0)
@@ -2153,14 +2167,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
return 0;
}
-static int pc_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int pc_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
digiflow_t dflow;
int retval;
@@ -2175,7 +2189,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
bc = ch->brdchan;
else
return -EINVAL;
-
/*
* For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
* /usr/src/linux/drivers/char for a good example. In particular think
@@ -2186,9 +2199,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
retval = tty_check_change(tty);
if (retval)
return retval;
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit
+ buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
if (!arg)
@@ -2198,29 +2212,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
retval = tty_check_change(tty);
if (retval)
return retval;
-
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit buffer
+ empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
return 0;
- case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
- return -EFAULT;
- return 0;
- case TIOCSSOFTCAR:
- {
- unsigned int value;
-
- if (get_user(value, (unsigned __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (value ? CLOCAL : 0));
- return 0;
- }
case TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
@@ -2253,10 +2252,12 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
break;
case DIGI_SETAW:
case DIGI_SETAF:
+ lock_kernel();
if (cmd == DIGI_SETAW) {
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit
+ buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
} else {
@@ -2264,6 +2265,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
}
+ unlock_kernel();
/* Fall Thru */
case DIGI_SETA:
if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
@@ -2285,7 +2287,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
* control issues, etc.... It effect both control flags and
* input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
break;
@@ -2321,18 +2323,21 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (copy_from_user(&dflow, argp, sizeof(dflow)))
return -EFAULT;
- if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
+ if (dflow.startc != startc || dflow.stopc != stopc) {
+ /* Begin if setflow toggled */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
if (cmd == DIGI_SETFLOW) {
ch->fepstartc = ch->startc = dflow.startc;
ch->fepstopc = ch->stopc = dflow.stopc;
- fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+ fepcmd(ch, SONOFFC, ch->fepstartc,
+ ch->fepstopc, 0, 1);
} else {
ch->fepstartca = ch->startca = dflow.startc;
ch->fepstopca = ch->stopca = dflow.stopc;
- fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca,
+ ch->fepstopca, 0, 1);
}
if (ch->statusflags & TXSTOPPED)
@@ -2356,7 +2361,9 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ ch = verifyChannel(tty);
+
+ if (ch != NULL) { /* Begin if channel valid */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
epcaparam(tty, ch);
@@ -2383,7 +2390,7 @@ static void do_softint(struct work_struct *work)
if (tty && tty->driver_data) {
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
- tty_hangup(tty); /* FIXME: module removal race here - AKPM */
+ tty_hangup(tty);
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
}
@@ -2403,9 +2410,11 @@ static void pc_stop(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
- if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
+ if ((ch->statusflags & TXSTOPPED) == 0) {
+ /* Begin if transmit stop requested */
globalwinon(ch);
/* STOP transmitting now !! */
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
@@ -2423,11 +2432,14 @@ static void pc_start(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
- /* Just in case output was resumed because of a change in Digi-flow */
- if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */
+ /* Just in case output was resumed because of a change
+ in Digi-flow */
+ if (ch->statusflags & TXSTOPPED) {
+ /* Begin transmit resume requested */
struct board_chan __iomem *bc;
globalwinon(ch);
bc = ch->brdchan;
@@ -2457,7 +2469,8 @@ static void pc_throttle(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
@@ -2477,8 +2490,10 @@ static void pc_unthrottle(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
- /* Just in case output was resumed because of a change in Digi-flow */
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
+ /* Just in case output was resumed because of a change
+ in Digi-flow */
spin_lock_irqsave(&epca_lock, flags);
if (ch->statusflags & RXSTOPPED) {
globalwinon(ch);
@@ -2490,7 +2505,7 @@ static void pc_unthrottle(struct tty_struct *tty)
}
}
-void digi_send_break(struct channel *ch, int msec)
+static void digi_send_break(struct channel *ch, int msec)
{
unsigned long flags;
@@ -2523,7 +2538,7 @@ static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
memoff(ch);
}
-void epca_setup(char *str, int *ints)
+static void epca_setup(char *str, int *ints)
{
struct board_info board;
int index, loop, last;
@@ -2552,14 +2567,16 @@ void epca_setup(char *str, int *ints)
* instructing the driver to ignore epcaconfig.) For
* this reason we check for 2.
*/
- if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
+ if (board.status == 2) {
+ /* Begin ignore epcaconfig as well as lilo cmd line */
nbdevs = 0;
num_cards = 0;
return;
} /* End ignore epcaconfig as well as lilo cmd line */
if (board.status > 2) {
- printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
+ board.status);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
@@ -2613,7 +2630,8 @@ void epca_setup(char *str, int *ints)
case 6:
board.membase = ints[index];
if (ints[index] <= 0) {
- printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
+ (unsigned int)board.membase);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -2744,7 +2762,7 @@ void epca_setup(char *str, int *ints)
t2++;
if (*t2) {
- printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -2766,7 +2784,7 @@ void epca_setup(char *str, int *ints)
/* I should REALLY validate the stuff here */
/* Copies our local copy of board into boards */
- memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
+ memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
/* Does this get called once per lilo arg are what ? */
printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
num_cards, board_desc[board.type],
@@ -2807,9 +2825,9 @@ static int __devinit epca_init_one(struct pci_dev *pdev,
if (board_idx >= MAXBOARDS)
goto err_out;
- addr = pci_resource_start (pdev, epca_info_tbl[info_idx].bar_idx);
+ addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
if (!addr) {
- printk (KERN_ERR PFX "PCI region #%d not available (size 0)\n",
+ printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
epca_info_tbl[info_idx].bar_idx);
goto err_out;
}
@@ -2820,28 +2838,29 @@ static int __devinit epca_init_one(struct pci_dev *pdev,
boards[board_idx].port = addr + PCI_IO_OFFSET;
boards[board_idx].membase = addr;
- if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
- printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
+ if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
+ printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out;
}
- boards[board_idx].re_map_port = ioremap(addr + PCI_IO_OFFSET, 0x200000);
+ boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
+ 0x200000);
if (!boards[board_idx].re_map_port) {
- printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
+ printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out_free_pciio;
}
- if (!request_mem_region (addr, 0x200000, "epca")) {
- printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
+ if (!request_mem_region(addr, 0x200000, "epca")) {
+ printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
0x200000, addr);
goto err_out_free_iounmap;
}
- boards[board_idx].re_map_membase = ioremap(addr, 0x200000);
+ boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
if (!boards[board_idx].re_map_membase) {
- printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
+ printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out_free_memregion;
}
@@ -2858,11 +2877,11 @@ static int __devinit epca_init_one(struct pci_dev *pdev,
return 0;
err_out_free_memregion:
- release_mem_region (addr, 0x200000);
+ release_mem_region(addr, 0x200000);
err_out_free_iounmap:
- iounmap (boards[board_idx].re_map_port);
+ iounmap(boards[board_idx].re_map_port);
err_out_free_pciio:
- release_mem_region (addr + PCI_IO_OFFSET, 0x200000);
+ release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
err_out:
return -ENODEV;
}
@@ -2878,9 +2897,9 @@ static struct pci_device_id epca_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
-int __init init_PCI (void)
+static int __init init_PCI(void)
{
- memset (&epca_driver, 0, sizeof (epca_driver));
+ memset(&epca_driver, 0, sizeof(epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
epca_driver.probe = epca_init_one;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index f3fe6206734..84840ba13ff 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -8,7 +8,7 @@
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
* 16450/16550A UART's. Added support for the AST FourPort and the
- * Accent Async board.
+ * Accent Async board.
*
* set_serial_info fixed to set the flags, custom divisor, and uart
* type fields. Fix suggested by Michael K. Johnson 12/12/92.
@@ -61,11 +61,11 @@
#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/hayesesp.h>
@@ -127,8 +127,10 @@ static struct tty_driver *esp_driver;
#undef SERIAL_DEBUG_FLOW
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s)
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ tty->name, info->flags, \
+ serial_driver.refcount, \
+ info->count, tty->count, s)
#else
#define DBG_CNT(s)
#endif
@@ -189,7 +191,7 @@ static inline void serial_out(struct esp_struct *info, int offset,
*/
static void rs_stop(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
@@ -206,12 +208,12 @@ static void rs_stop(struct tty_struct *tty)
static void rs_start(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
@@ -233,7 +235,7 @@ static void rs_start(struct tty_struct *tty)
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
- *
+ *
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
@@ -290,7 +292,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
}
status_mask = (info->read_status_mask >> 2) & 0x07;
-
+
for (i = 0; i < num_bytes - 1; i += 2) {
*((unsigned short *)(pio_buf->data + i)) =
inw(info->port + UART_ESI_RX);
@@ -325,8 +327,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
flag = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
- }
- else if (err_buf->data[i] & 0x02)
+ } else if (err_buf->data[i] & 0x02)
flag = TTY_FRAME;
else if (err_buf->data[i] & 0x01)
flag = TTY_PARITY;
@@ -341,23 +342,29 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
release_pio_buffer(err_buf);
}
-static inline void receive_chars_dma(struct esp_struct *info, int num_bytes)
+static void program_isa_dma(int dma, int dir, unsigned long addr, int len)
{
unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(dma);
+ clear_dma_ff(dma);
+ set_dma_mode(dma, dir);
+ set_dma_addr(dma, addr);
+ set_dma_count(dma, len);
+ enable_dma(dma);
+ release_dma_lock(flags);
+}
+
+static void receive_chars_dma(struct esp_struct *info, int num_bytes)
+{
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
dma_bytes = num_bytes;
info->stat_flags |= ESP_STAT_DMA_RX;
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_READ);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
+
+ program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer),
+ dma_bytes);
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
}
static inline void receive_chars_dma_done(struct esp_struct *info,
@@ -366,22 +373,22 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
struct tty_struct *tty = info->tty;
int num_bytes;
unsigned long flags;
-
- flags=claim_dma_lock();
+
+ flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
info->stat_flags &= ~ESP_STAT_DMA_RX;
num_bytes = dma_bytes - get_dma_residue(dma);
release_dma_lock(flags);
-
+
info->icount.rx += num_bytes;
if (num_bytes > 0) {
tty_insert_flip_string(tty, dma_buffer, num_bytes - 1);
status &= (0x1c & info->read_status_mask);
-
+
/* Is the status significant or do we throw the last byte ? */
if (!(status & info->ignore_status_mask)) {
int statflag = 0;
@@ -393,13 +400,13 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
do_SAK(tty);
} else if (status & 0x08) {
statflag = TTY_FRAME;
- (info->icount.frame)++;
- }
- else if (status & 0x04) {
+ info->icount.frame++;
+ } else if (status & 0x04) {
statflag = TTY_PARITY;
- (info->icount.parity)++;
+ info->icount.parity++;
}
- tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
+ tty_insert_flip_char(tty, dma_buffer[num_bytes - 1],
+ statflag);
}
tty_schedule_flip(tty);
}
@@ -484,8 +491,6 @@ static inline void transmit_chars_pio(struct esp_struct *info,
/* Caller must hold info->lock */
static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
{
- unsigned long flags;
-
dma_bytes = num_bytes;
if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
@@ -517,26 +522,18 @@ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
}
info->stat_flags |= ESP_STAT_DMA_TX;
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_WRITE);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
+
+ program_isa_dma(dma, DMA_MODE_WRITE, isa_virt_to_bus(dma_buffer),
+ dma_bytes);
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
}
static inline void transmit_chars_dma_done(struct esp_struct *info)
{
int num_bytes;
unsigned long flags;
-
- flags=claim_dma_lock();
+ flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
@@ -547,27 +544,21 @@ static inline void transmit_chars_dma_done(struct esp_struct *info)
if (dma_bytes != num_bytes) {
dma_bytes -= num_bytes;
memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes);
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_WRITE);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
+
+ program_isa_dma(dma, DMA_MODE_WRITE,
+ isa_virt_to_bus(dma_buffer), dma_bytes);
+
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
} else {
dma_bytes = 0;
info->stat_flags &= ~ESP_STAT_DMA_TX;
}
}
-static inline void check_modem_status(struct esp_struct *info)
+static void check_modem_status(struct esp_struct *info)
{
int status;
-
+
serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
status = serial_in(info, UART_ESI_STAT2);
@@ -588,7 +579,7 @@ static inline void check_modem_status(struct esp_struct *info)
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
-#endif
+#endif
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
else {
@@ -605,7 +596,7 @@ static inline void check_modem_status(struct esp_struct *info)
*/
static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{
- struct esp_struct * info;
+ struct esp_struct *info;
unsigned err_status;
unsigned int scratch;
@@ -617,7 +608,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
scratch = serial_in(info, UART_ESI_SID);
spin_lock(&info->lock);
-
+
if (!info->tty) {
spin_unlock(&info->lock);
return IRQ_NONE;
@@ -637,7 +628,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
if (err_status & 0x80) /* Start break */
wake_up_interruptible(&info->break_wait);
}
-
+
if ((scratch & 0x88) || /* DMA completed or timed out */
(err_status & 0x1c) /* receive error */) {
if (info->stat_flags & ESP_STAT_DMA_RX)
@@ -667,7 +658,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
receive_chars_dma(info, num_bytes);
}
}
-
+
if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
(scratch & 0x02) && (info->IER & UART_IER_THRI)) {
if ((info->xmit_cnt <= 0) || info->tty->stopped) {
@@ -722,11 +713,11 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
* ---------------------------------------------------------------
*/
-static inline void esp_basic_init(struct esp_struct * info)
+static void esp_basic_init(struct esp_struct *info)
{
/* put ESPC in enhanced mode */
serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
-
+
if (info->stat_flags & ESP_STAT_NEVER_DMA)
serial_out(info, UART_ESI_CMD2, 0x01);
else
@@ -783,13 +774,13 @@ static inline void esp_basic_init(struct esp_struct * info)
serial_out(info, UART_ESI_CMD2, 0xff);
}
-static int startup(struct esp_struct * info)
+static int startup(struct esp_struct *info)
{
unsigned long flags;
- int retval=0;
- unsigned int num_chars;
+ int retval = 0;
+ unsigned int num_chars;
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->flags & ASYNC_INITIALIZED)
goto out;
@@ -802,7 +793,8 @@ static int startup(struct esp_struct * info)
}
#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+ printk(KERN_DEBUG "starting up ttys%d (irq %d)...",
+ info->line, info->irq);
#endif
/* Flush the RX buffer. Using the ESI flush command may cause */
@@ -863,7 +855,7 @@ static int startup(struct esp_struct * info)
dma_buffer = NULL;
info->stat_flags |= ESP_STAT_USE_PIO;
}
-
+
}
info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
@@ -872,7 +864,7 @@ static int startup(struct esp_struct * info)
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR);
-
+
/*
* Finally, enable interrupts
*/
@@ -881,7 +873,7 @@ static int startup(struct esp_struct * info)
UART_IER_DMA_TC;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
-
+
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
@@ -900,7 +892,7 @@ static int startup(struct esp_struct * info)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
-
+
/*
* set the speed of the serial port
*/
@@ -918,7 +910,7 @@ out_unlocked:
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct esp_struct * info)
+static void shutdown(struct esp_struct *info)
{
unsigned long flags, f;
@@ -929,7 +921,7 @@ static void shutdown(struct esp_struct * info)
printk("Shutting down serial port %d (irq %d)....", info->line,
info->irq);
#endif
-
+
spin_lock_irqsave(&info->lock, flags);
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
@@ -941,14 +933,14 @@ static void shutdown(struct esp_struct * info)
/* stop a DMA transfer on the port being closed */
/* DMA lock is higher priority always */
if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
- f=claim_dma_lock();
+ f = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
release_dma_lock(f);
-
+
dma_bytes = 0;
}
-
+
/*
* Free the IRQ
*/
@@ -970,7 +962,7 @@ static void shutdown(struct esp_struct * info)
free_pages((unsigned long)dma_buffer,
get_order(DMA_BUFFER_SZ));
dma_buffer = NULL;
- }
+ }
}
if (info->xmit_buf) {
@@ -992,7 +984,7 @@ static void shutdown(struct esp_struct * info)
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
-
+
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&info->lock, flags);
}
@@ -1005,7 +997,7 @@ static void change_speed(struct esp_struct *info)
{
unsigned short port;
int quot = 0;
- unsigned cflag,cval;
+ unsigned cflag, cval;
int baud, bits;
unsigned char flow1 = 0, flow2 = 0;
unsigned long flags;
@@ -1014,14 +1006,14 @@ static void change_speed(struct esp_struct *info)
return;
cflag = info->tty->termios->c_cflag;
port = info->port;
-
+
/* byte size and parity */
switch (cflag & CSIZE) {
- case CS5: cval = 0x00; bits = 7; break;
- case CS6: cval = 0x01; bits = 8; break;
- case CS7: cval = 0x02; bits = 9; break;
- case CS8: cval = 0x03; bits = 10; break;
- default: cval = 0x00; bits = 7; break;
+ case CS5: cval = 0x00; bits = 7; break;
+ case CS6: cval = 0x01; bits = 8; break;
+ case CS7: cval = 0x02; bits = 9; break;
+ case CS8: cval = 0x03; bits = 10; break;
+ default: cval = 0x00; bits = 7; break;
}
if (cflag & CSTOPB) {
cval |= 0x04;
@@ -1037,14 +1029,12 @@ static void change_speed(struct esp_struct *info)
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
-
baud = tty_get_baud_rate(info->tty);
if (baud == 38400 &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->custom_divisor;
else {
- if (baud == 134)
- /* Special case since 134 is really 134.5 */
+ if (baud == 134) /* Special case since 134 is really 134.5 */
quot = (2*BASE_BAUD / 269);
else if (baud)
quot = BASE_BAUD / baud;
@@ -1052,7 +1042,12 @@ static void change_speed(struct esp_struct *info)
/* If the quotient is ever zero, default to 9600 bps */
if (!quot)
quot = BASE_BAUD / 9600;
-
+
+ if (baud) {
+ /* Actual rate */
+ baud = BASE_BAUD/quot;
+ tty_encode_baud_rate(info->tty, baud, baud);
+ }
info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);
/* CTS flow control flag and modem status interrupts */
@@ -1066,10 +1061,8 @@ static void change_speed(struct esp_struct *info)
info->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
- else {
+ else
info->flags |= ASYNC_CHECK_CD;
- /* info->IER |= UART_IER_MSI; */
- }
/*
* Set up parity check flag
@@ -1079,7 +1072,7 @@ static void change_speed(struct esp_struct *info)
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= UART_LSR_BI;
-
+
info->ignore_status_mask = 0;
#if 0
/* This should be safe, but for some broken bits of hardware... */
@@ -1092,7 +1085,7 @@ static void change_speed(struct esp_struct *info)
info->ignore_status_mask |= UART_LSR_BI;
info->read_status_mask |= UART_LSR_BI;
/*
- * If we're ignore parity and break indicators, ignore
+ * If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty)) {
@@ -1130,19 +1123,19 @@ static void change_speed(struct esp_struct *info)
serial_out(info, UART_ESI_CMD2, 0x10);
serial_out(info, UART_ESI_CMD2, 0x21);
switch (cflag & CSIZE) {
- case CS5:
- serial_out(info, UART_ESI_CMD2, 0x1f);
- break;
- case CS6:
- serial_out(info, UART_ESI_CMD2, 0x3f);
- break;
- case CS7:
- case CS8:
- serial_out(info, UART_ESI_CMD2, 0x7f);
- break;
- default:
- serial_out(info, UART_ESI_CMD2, 0xff);
- break;
+ case CS5:
+ serial_out(info, UART_ESI_CMD2, 0x1f);
+ break;
+ case CS6:
+ serial_out(info, UART_ESI_CMD2, 0x3f);
+ break;
+ case CS7:
+ case CS8:
+ serial_out(info, UART_ESI_CMD2, 0x7f);
+ break;
+ default:
+ serial_out(info, UART_ESI_CMD2, 0xff);
+ break;
}
}
@@ -1156,31 +1149,34 @@ static void change_speed(struct esp_struct *info)
spin_unlock_irqrestore(&info->lock, flags);
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= ESP_XMIT_SIZE-1;
info->xmit_cnt++;
+ ret = 1;
}
spin_unlock_irqrestore(&info->lock, flags);
+ return ret;
}
static void rs_flush_chars(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
return;
@@ -1198,11 +1194,11 @@ out:
spin_unlock_irqrestore(&info->lock, flags);
}
-static int rs_write(struct tty_struct * tty,
+static int rs_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
int c, t, ret = 0;
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_write"))
@@ -1210,19 +1206,19 @@ static int rs_write(struct tty_struct * tty,
if (!info->xmit_buf)
return 0;
-
+
while (1) {
/* Thanks to R. Wolff for suggesting how to do this with */
/* interrupts enabled */
c = count;
t = ESP_XMIT_SIZE - info->xmit_cnt - 1;
-
+
if (t < c)
c = t;
t = ESP_XMIT_SIZE - info->xmit_head;
-
+
if (t < c)
c = t;
@@ -1252,10 +1248,10 @@ static int rs_write(struct tty_struct * tty,
static int rs_write_room(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
int ret;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
@@ -1270,8 +1266,8 @@ static int rs_write_room(struct tty_struct *tty)
static int rs_chars_in_buffer(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
-
+ struct esp_struct *info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
return info->xmit_cnt;
@@ -1279,9 +1275,9 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_flush_buffer(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
spin_lock_irqsave(&info->lock, flags);
@@ -1293,20 +1289,20 @@ static void rs_flush_buffer(struct tty_struct *tty)
/*
* ------------------------------------------------------------
* rs_throttle()
- *
+ *
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
-static void rs_throttle(struct tty_struct * tty)
+static void rs_throttle(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
+
printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
+ tty_chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
@@ -1321,20 +1317,20 @@ static void rs_throttle(struct tty_struct * tty)
spin_unlock_irqrestore(&info->lock, flags);
}
-static void rs_unthrottle(struct tty_struct * tty)
+static void rs_unthrottle(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
- printk("unthrottle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
+
+ printk(KERN_DEBUG "unthrottle %s: %d....\n", tty_name(tty, buf),
+ tty_chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
info->IER |= UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
@@ -1350,11 +1346,12 @@ static void rs_unthrottle(struct tty_struct * tty)
* ------------------------------------------------------------
*/
-static int get_serial_info(struct esp_struct * info,
+static int get_serial_info(struct esp_struct *info,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
-
+
+ lock_kernel();
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
tmp.line = info->line;
@@ -1367,20 +1364,22 @@ static int get_serial_info(struct esp_struct * info,
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = 0;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ unlock_kernel();
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
}
-static int get_esp_config(struct esp_struct * info,
+static int get_esp_config(struct esp_struct *info,
struct hayes_esp_config __user *retinfo)
{
struct hayes_esp_config tmp;
-
+
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.rx_timeout = info->config.rx_timeout;
tmp.rx_trigger = info->config.rx_trigger;
tmp.tx_trigger = info->config.tx_trigger;
@@ -1388,11 +1387,12 @@ static int get_esp_config(struct esp_struct * info,
tmp.flow_on = info->config.flow_on;
tmp.pio_threshold = info->config.pio_threshold;
tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma);
+ unlock_kernel();
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
-static int set_serial_info(struct esp_struct * info,
+static int set_serial_info(struct esp_struct *info,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
@@ -1401,7 +1401,7 @@ static int set_serial_info(struct esp_struct * info,
int retval = 0;
struct esp_struct *current_async;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
old_info = *info;
@@ -1422,7 +1422,7 @@ static int set_serial_info(struct esp_struct * info,
return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) {
- if (change_irq ||
+ if (change_irq ||
(new_serial.close_delay != info->close_delay) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->flags & ~ASYNC_USR_MASK)))
@@ -1507,8 +1507,8 @@ static int set_serial_info(struct esp_struct * info,
return retval;
}
-static int set_esp_config(struct esp_struct * info,
- struct hayes_esp_config __user * new_info)
+static int set_esp_config(struct esp_struct *info,
+ struct hayes_esp_config __user *new_info)
{
struct hayes_esp_config new_config;
unsigned int change_dma;
@@ -1550,7 +1550,6 @@ static int set_esp_config(struct esp_struct * info,
if (new_config.dma_channel) {
/* PIO mode to DMA mode transition OR */
/* change current DMA channel */
-
current_async = ports;
while (current_async) {
@@ -1559,16 +1558,15 @@ static int set_esp_config(struct esp_struct * info,
return -EBUSY;
} else if (current_async->count)
return -EBUSY;
-
- current_async =
- current_async->next_port;
+
+ current_async = current_async->next_port;
}
shutdown(info);
dma = new_config.dma_channel;
info->stat_flags &= ~ESP_STAT_NEVER_DMA;
-
- /* all ports must use the same DMA channel */
+
+ /* all ports must use the same DMA channel */
spin_lock_irqsave(&info->lock, flags);
current_async = ports;
@@ -1580,7 +1578,6 @@ static int set_esp_config(struct esp_struct * info,
spin_unlock_irqrestore(&info->lock, flags);
} else {
/* DMA mode to PIO mode only */
-
if (info->count > 1)
return -EBUSY;
@@ -1596,8 +1593,6 @@ static int set_esp_config(struct esp_struct * info,
if ((new_config.flow_off != info->config.flow_off) ||
(new_config.flow_on != info->config.flow_on)) {
- unsigned long flags;
-
info->config.flow_off = new_config.flow_off;
info->config.flow_on = new_config.flow_on;
@@ -1612,8 +1607,6 @@ static int set_esp_config(struct esp_struct * info,
if ((new_config.rx_trigger != info->config.rx_trigger) ||
(new_config.tx_trigger != info->config.tx_trigger)) {
- unsigned long flags;
-
info->config.rx_trigger = new_config.rx_trigger;
info->config.tx_trigger = new_config.tx_trigger;
spin_lock_irqsave(&info->lock, flags);
@@ -1628,8 +1621,6 @@ static int set_esp_config(struct esp_struct * info,
}
if (new_config.rx_timeout != info->config.rx_timeout) {
- unsigned long flags;
-
info->config.rx_timeout = new_config.rx_timeout;
spin_lock_irqsave(&info->lock, flags);
@@ -1657,9 +1648,9 @@ static int set_esp_config(struct esp_struct * info,
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
+ * allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
+static int get_lsr_info(struct esp_struct *info, unsigned int __user *value)
{
unsigned char status;
unsigned int result;
@@ -1670,17 +1661,17 @@ static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
status = serial_in(info, UART_ESI_STAT1);
spin_unlock_irqrestore(&info->lock, flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
+ return put_user(result, value);
}
static int esp_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned char control, status;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1703,10 +1694,10 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file)
static int esp_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1736,9 +1727,9 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
*/
static void esp_break(struct tty_struct *tty, int break_state)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "esp_break"))
return;
@@ -1758,14 +1749,15 @@ static void esp_break(struct tty_struct *tty, int break_state)
}
}
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
+static int rs_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg;
unsigned long flags;
+ int ret;
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
@@ -1778,97 +1770,93 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(info, argp);
- case TIOCSSERIAL:
- return set_serial_info(info, argp);
- case TIOCSERCONFIG:
- /* do not reconfigure after initial configuration */
- return 0;
-
- case TIOCSERGWILD:
- return put_user(0L, (unsigned long __user *)argp);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, argp);
-
- case TIOCSERSWILD:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- return 0;
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ lock_kernel();
+ ret = set_serial_info(info, argp);
+ unlock_kernel();
+ return ret;
+ case TIOCSERGWILD:
+ return put_user(0L, (unsigned long __user *)argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, argp);
+ case TIOCSERSWILD:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ spin_lock_irqsave(&info->lock, flags);
+ cprev = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->lock, flags);
+ while (1) {
+ /* FIXME: convert to new style wakeup */
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
spin_lock_irqsave(&info->lock, flags);
- cprev = info->icount; /* note the counters on entry */
+ cnow = info->icount; /* atomic copy */
spin_unlock_irqrestore(&info->lock, flags);
- while (1) {
- /* FIXME: convert to new style wakeup */
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irqsave(&info->lock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->lock, flags);
- if (cnow.rng == cprev.rng &&
- cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd &&
- cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) &&
- (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) &&
- (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) &&
- (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) &&
- (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
+ if (cnow.rng == cprev.rng &&
+ cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd &&
+ cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) &&
+ (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) &&
+ (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) &&
+ (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) &&
+ (cnow.cts != cprev.cts))) {
+ return 0;
}
- /* NOTREACHED */
-
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- case TIOCGICOUNT:
- spin_lock_irqsave(&info->lock, flags);
- cnow = info->icount;
- spin_unlock_irqrestore(&info->lock, flags);
- p_cuser = argp;
- if (put_user(cnow.cts, &p_cuser->cts) ||
- put_user(cnow.dsr, &p_cuser->dsr) ||
- put_user(cnow.rng, &p_cuser->rng) ||
- put_user(cnow.dcd, &p_cuser->dcd))
- return -EFAULT;
-
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->lock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->lock, flags);
+ p_cuser = argp;
+ if (put_user(cnow.cts, &p_cuser->cts) ||
+ put_user(cnow.dsr, &p_cuser->dsr) ||
+ put_user(cnow.rng, &p_cuser->rng) ||
+ put_user(cnow.dcd, &p_cuser->dcd))
+ return -EFAULT;
return 0;
case TIOCGHAYESESP:
return get_esp_config(info, argp);
case TIOCSHAYESESP:
- return set_esp_config(info, argp);
-
- default:
- return -ENOIOCTLCMD;
- }
+ lock_kernel();
+ ret = set_esp_config(info, argp);
+ unlock_kernel();
+ return ret;
+ default:
+ return -ENOIOCTLCMD;
+ }
return 0;
}
static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
change_speed(info);
@@ -1905,32 +1893,33 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/*
* ------------------------------------------------------------
* rs_close()
- *
+ *
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
* async structure from the interrupt chain if necessary, and we free
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
-static void rs_close(struct tty_struct *tty, struct file * filp)
+static void rs_close(struct tty_struct *tty, struct file *filp)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
-
+
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
goto out;
}
-
+
#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+ printk(KERN_DEBUG "rs_close ttys%d, count = %d\n",
+ info->line, info->count);
#endif
- if ((tty->count == 1) && (info->count != 1)) {
+ if (tty->count == 1 && info->count != 1) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -1938,12 +1927,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk("rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
+ printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
- printk("rs_close: bad serial port count for ttys%d: %d\n",
+ printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
info->line, info->count);
info->count = 0;
}
@@ -1955,7 +1943,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
spin_unlock_irqrestore(&info->lock, flags);
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
@@ -1990,16 +1978,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
rs_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
info->tty = NULL;
if (info->blocked_open) {
- if (info->close_delay) {
+ if (info->close_delay)
msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
@@ -2012,7 +1998,7 @@ out:
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
unsigned long flags;
@@ -2036,10 +2022,10 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
- break;
+ return;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
+ return;
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
@@ -2054,11 +2040,11 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
*/
static void esp_hangup(struct tty_struct *tty)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
-
+ struct esp_struct *info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "esp_hangup"))
return;
-
+
rs_flush_buffer(tty);
shutdown(info);
info->count = 0;
@@ -2072,7 +2058,7 @@ static void esp_hangup(struct tty_struct *tty)
* esp_open() and friends
* ------------------------------------------------------------
*/
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct esp_struct *info)
{
DECLARE_WAITQUEUE(wait, current);
@@ -2121,11 +2107,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n",
info->line, info->count);
#endif
spin_lock_irqsave(&info->lock, flags);
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp))
info->count--;
info->blocked_open++;
while (1) {
@@ -2147,7 +2133,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if (info->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
@@ -2166,7 +2152,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
break;
}
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
spin_unlock_irqrestore(&info->lock, flags);
@@ -2180,14 +2166,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
info->blocked_open--;
spin_unlock_irqrestore(&info->lock, flags);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
if (retval)
return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
-}
+}
/*
* This routine is called whenever a serial port is opened. It
@@ -2195,7 +2181,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
-static int esp_open(struct tty_struct *tty, struct file * filp)
+static int esp_open(struct tty_struct *tty, struct file *filp)
{
struct esp_struct *info;
int retval, line;
@@ -2218,7 +2204,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
}
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open %s, count = %d\n", tty->name, info->count);
+ printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->count);
#endif
spin_lock_irqsave(&info->lock, flags);
info->count++;
@@ -2226,7 +2212,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
info->tty = tty;
spin_unlock_irqrestore(&info->lock, flags);
-
+
/*
* Start up serial port
*/
@@ -2237,14 +2223,13 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open returning after block_til_ready with %d\n",
+ printk(KERN_DEBUG "esp_open returning after block_til_ready with %d\n",
retval);
#endif
return retval;
}
-
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open %s successful...", tty->name);
+ printk(KERN_DEBUG "esp_open %s successful...", tty->name);
#endif
return 0;
}
@@ -2262,10 +2247,10 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
* number, and identifies which options were configured into this
* driver.
*/
-
-static inline void show_serial_version(void)
+
+static void show_serial_version(void)
{
- printk(KERN_INFO "%s version %s (DMA %u)\n",
+ printk(KERN_INFO "%s version %s (DMA %u)\n",
serial_name, serial_version, dma);
}
@@ -2273,7 +2258,7 @@ static inline void show_serial_version(void)
* This routine is called by espserial_init() to initialize a specific serial
* port.
*/
-static inline int autoconfig(struct esp_struct * info)
+static int autoconfig(struct esp_struct *info)
{
int port_detected = 0;
unsigned long flags;
@@ -2349,14 +2334,14 @@ static const struct tty_operations esp_ops = {
static int __init espserial_init(void)
{
int i, offset;
- struct esp_struct * info;
+ struct esp_struct *info;
struct esp_struct *last_primary = NULL;
- int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
+ int esp[] = { 0x100, 0x140, 0x180, 0x200, 0x240, 0x280, 0x300, 0x380 };
esp_driver = alloc_tty_driver(NR_PORTS);
if (!esp_driver)
return -ENOMEM;
-
+
for (i = 0; i < NR_PRIMARY; i++) {
if (irq[i] != 0) {
if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
@@ -2378,20 +2363,20 @@ static int __init espserial_init(void)
if ((flow_off < 1) || (flow_off > 1023))
flow_off = 1016;
-
+
if ((flow_on < 1) || (flow_on > 1023))
flow_on = 944;
if ((rx_timeout < 0) || (rx_timeout > 255))
rx_timeout = 128;
-
+
if (flow_on >= flow_off)
flow_on = flow_off - 1;
show_serial_version();
/* Initialize the tty_driver structure */
-
+
esp_driver->owner = THIS_MODULE;
esp_driver->name = "ttyP";
esp_driver->major = ESP_IN_MAJOR;
@@ -2401,10 +2386,11 @@ static int __init espserial_init(void)
esp_driver->init_termios = tty_std_termios;
esp_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ esp_driver->init_termios.c_ispeed = 9600;
+ esp_driver->init_termios.c_ospeed = 9600;
esp_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(esp_driver, &esp_ops);
- if (tty_register_driver(esp_driver))
- {
+ if (tty_register_driver(esp_driver)) {
printk(KERN_ERR "Couldn't register esp serial driver");
put_tty_driver(esp_driver);
return 1;
@@ -2412,8 +2398,7 @@ static int __init espserial_init(void)
info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
- if (!info)
- {
+ if (!info) {
printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
tty_unregister_driver(esp_driver);
put_tty_driver(esp_driver);
@@ -2476,10 +2461,8 @@ static int __init espserial_init(void)
info->stat_flags |= ESP_STAT_NEVER_DMA;
info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
- if (!info)
- {
- printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
-
+ if (!info) {
+ printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
/* allow use of the already detected ports */
return 0;
}
@@ -2503,22 +2486,20 @@ static int __init espserial_init(void)
return 0;
}
-static void __exit espserial_exit(void)
+static void __exit espserial_exit(void)
{
int e1;
struct esp_struct *temp_async;
struct esp_pio_buffer *pio_buf;
- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- if ((e1 = tty_unregister_driver(esp_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
- e1);
+ e1 = tty_unregister_driver(esp_driver);
+ if (e1)
+ printk(KERN_ERR "esp: failed to unregister driver (%d)\n", e1);
put_tty_driver(esp_driver);
while (ports) {
- if (ports->port) {
+ if (ports->port)
release_region(ports->port, REGION_SIZE);
- }
temp_async = ports->next_port;
kfree(ports);
ports = temp_async;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 7ed7da1d99c..252f73e4859 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -40,27 +40,27 @@ static int gs_debug;
#define gs_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
-#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__)
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __func__)
+#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __func__)
#define RS_EVENT_WRITE_WAKEUP 1
module_param(gs_debug, int, 0644);
-void gs_put_char(struct tty_struct * tty, unsigned char ch)
+int gs_put_char(struct tty_struct * tty, unsigned char ch)
{
struct gs_port *port;
func_enter ();
- if (!tty) return;
+ if (!tty) return 0;
port = tty->driver_data;
- if (!port) return;
+ if (!port) return 0;
- if (! (port->flags & ASYNC_INITIALIZED)) return;
+ if (! (port->flags & ASYNC_INITIALIZED)) return 0;
/* Take a lock on the serial tranmit buffer! */
mutex_lock(& port->port_write_mutex);
@@ -68,7 +68,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
/* Sorry, buffer is full, drop character. Update statistics???? -- REW */
mutex_unlock(&port->port_write_mutex);
- return;
+ return 0;
}
port->xmit_buf[port->xmit_head++] = ch;
@@ -77,6 +77,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
mutex_unlock(&port->port_write_mutex);
func_exit ();
+ return 1;
}
@@ -586,8 +587,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
port->flags &= ~GS_ACTIVE;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ gs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 1399971be68..e7fb0bca366 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -308,7 +308,7 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
- __FUNCTION__);
+ __func__);
return -EAGAIN;
}
@@ -748,7 +748,7 @@ int hpet_alloc(struct hpet_data *hdp)
*/
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: duplicate HPET ignored\n",
- __FUNCTION__);
+ __func__);
return 0;
}
@@ -869,7 +869,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __FUNCTION__, hdp->hd_phys_address);
+ __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -886,7 +886,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __FUNCTION__, hdp->hd_phys_address);
+ __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -925,7 +925,7 @@ static int hpet_acpi_add(struct acpi_device *device)
return -ENODEV;
if (!data.hd_address || !data.hd_nirqs) {
- printk("%s: no address or irqs in _CRS\n", __FUNCTION__);
+ printk("%s: no address or irqs in _CRS\n", __func__);
return -ENODEV;
}
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index d5a752da322..59c6f9ab94e 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -246,7 +246,7 @@ static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to)
{
int remaining = (int)(hp->inbuf_end - read_to);
- pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining);
+ pr_debug("%s: %i chars remain\n", __func__, remaining);
if (read_to != hp->inbuf)
memmove(hp->inbuf, read_to, remaining);
@@ -365,7 +365,7 @@ static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno)
packet.u.version = HVSI_VERSION;
packet.query_seqno = query_seqno+1;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -437,7 +437,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
return NULL;
if (overflow > 0) {
- pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__);
+ pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE;
}
@@ -448,7 +448,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
* we still have more data to deliver, so we need to save off the
* overflow and send it later
*/
- pr_debug("%s: deferring overflow\n", __FUNCTION__);
+ pr_debug("%s: deferring overflow\n", __func__);
memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow);
hp->n_throttle = overflow;
}
@@ -474,11 +474,11 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
if (chunklen == 0) {
- pr_debug("%s: 0-length read\n", __FUNCTION__);
+ pr_debug("%s: 0-length read\n", __func__);
return 0;
}
- pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen);
+ pr_debug("%s: got %i bytes\n", __func__, chunklen);
dbg_dump_hex(hp->inbuf_end, chunklen);
hp->inbuf_end += chunklen;
@@ -495,7 +495,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
continue;
}
- pr_debug("%s: handling %i-byte packet\n", __FUNCTION__,
+ pr_debug("%s: handling %i-byte packet\n", __func__,
len_packet(packet));
dbg_dump_packet(packet);
@@ -526,7 +526,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
packet += len_packet(packet);
if (*hangup || *handshake) {
- pr_debug("%s: hangup or handshake\n", __FUNCTION__);
+ pr_debug("%s: hangup or handshake\n", __func__);
/*
* we need to send the hangup now before receiving any more data.
* If we get "data, hangup, data", we can't deliver the second
@@ -543,7 +543,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
static void hvsi_send_overflow(struct hvsi_struct *hp)
{
- pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__,
+ pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle);
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
@@ -563,7 +563,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
unsigned long flags;
int again = 1;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
while (again) {
spin_lock_irqsave(&hp->lock, flags);
@@ -647,7 +647,7 @@ static int hvsi_query(struct hvsi_struct *hp, uint16_t verb)
packet.seqno = atomic_inc_return(&hp->seqno);
packet.verb = verb;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -674,7 +674,7 @@ static int hvsi_get_mctrl(struct hvsi_struct *hp)
return ret;
}
- pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl);
+ pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl);
return 0;
}
@@ -694,7 +694,7 @@ static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl)
if (mctrl & TIOCM_DTR)
packet.word = HVSI_TSDTR;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -790,7 +790,7 @@ static void hvsi_close_protocol(struct hvsi_struct *hp)
packet.len = 6;
packet.verb = VSV_CLOSE_PROTOCOL;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -803,7 +803,7 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
int line = tty->index;
int ret;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
if (line < 0 || line >= hvsi_count)
return -ENODEV;
@@ -868,7 +868,7 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
if (tty_hung_up_p(filp))
return;
@@ -920,7 +920,7 @@ static void hvsi_hangup(struct tty_struct *tty)
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
@@ -942,7 +942,7 @@ static void hvsi_push(struct hvsi_struct *hp)
n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf);
if (n > 0) {
/* success */
- pr_debug("%s: wrote %i chars\n", __FUNCTION__, n);
+ pr_debug("%s: wrote %i chars\n", __func__, n);
hp->n_outbuf = 0;
} else if (n == -EIO) {
__set_state(hp, HVSI_FSP_DIED);
@@ -965,7 +965,7 @@ static void hvsi_write_worker(struct work_struct *work)
spin_lock_irqsave(&hp->lock, flags);
- pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf);
+ pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
if (!is_open(hp)) {
/*
@@ -983,7 +983,7 @@ static void hvsi_write_worker(struct work_struct *work)
schedule_delayed_work(&hp->writer, 10);
else {
#ifdef DEBUG
- pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__,
+ pr_debug("%s: outbuf emptied after %li jiffies\n", __func__,
jiffies - start_j);
start_j = 0;
#endif /* DEBUG */
@@ -1020,11 +1020,11 @@ static int hvsi_write(struct tty_struct *tty,
spin_lock_irqsave(&hp->lock, flags);
- pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf);
+ pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
if (!is_open(hp)) {
/* we're either closing or not yet open; don't accept data */
- pr_debug("%s: not open\n", __FUNCTION__);
+ pr_debug("%s: not open\n", __func__);
goto out;
}
@@ -1058,7 +1058,7 @@ out:
spin_unlock_irqrestore(&hp->lock, flags);
if (total != origcount)
- pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount,
+ pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount,
total);
return total;
@@ -1072,7 +1072,7 @@ static void hvsi_throttle(struct tty_struct *tty)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE);
}
@@ -1083,7 +1083,7 @@ static void hvsi_unthrottle(struct tty_struct *tty)
unsigned long flags;
int shouldflip = 0;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) {
@@ -1302,7 +1302,7 @@ static int __init hvsi_console_init(void)
hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
- __FUNCTION__, irq[0]);
+ __func__, irq[0]);
continue;
}
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index 61ef013b844..3601017f58c 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -53,7 +53,7 @@ static int ii2Safe; // Safe I/O address for delay routine
static int iiDelayed; // Set when the iiResetDelay function is
// called. Cleared when ANY board is reset.
-static rwlock_t Dl_spinlock;
+static DEFINE_RWLOCK(Dl_spinlock);
//********
//* Code *
@@ -82,7 +82,6 @@ static rwlock_t Dl_spinlock;
static void
iiEllisInit(void)
{
- LOCK_INIT(&Dl_spinlock);
}
//******************************************************************************
@@ -132,7 +131,7 @@ iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay )
|| (address & 0x7)
)
{
- COMPLETE(pB,I2EE_BADADDR);
+ I2_COMPLETE(pB, I2EE_BADADDR);
}
// Initialize accelerators
@@ -152,7 +151,7 @@ iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay )
pB->i2eValid = I2E_MAGIC;
pB->i2eState = II_STATE_COLD;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -177,12 +176,12 @@ iiReset(i2eBordStrPtr pB)
// Magic number should be set, else even the address is suspect
if (pB->i2eValid != I2E_MAGIC)
{
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
- OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do
+ outb(0, pB->i2eBase + FIFO_RESET); /* Any data will do */
iiDelay(pB, 50); // Pause between resets
- OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset
+ outb(0, pB->i2eBase + FIFO_RESET); /* Second reset */
// We must wait before even attempting to read anything from the FIFO: the
// board's P.O.S.T may actually attempt to read and write its end of the
@@ -203,7 +202,7 @@ iiReset(i2eBordStrPtr pB)
// Ensure anything which would have been of use to standard loadware is
// blanked out, since board has now forgotten everything!.
- pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet
+ pB->i2eUsingIrq = I2_IRQ_UNDEFINED; /* to not use an interrupt so far */
pB->i2eWaitingForEmptyFifo = 0;
pB->i2eOutMailWaiting = 0;
pB->i2eChannelPtr = NULL;
@@ -215,7 +214,7 @@ iiReset(i2eBordStrPtr pB)
pB->i2eFatalTrap = NULL;
pB->i2eFatal = 0;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -235,14 +234,14 @@ static int
iiResetDelay(i2eBordStrPtr pB)
{
if (pB->i2eValid != I2E_MAGIC) {
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_RESET) {
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
iiDelay(pB,2000); /* Now we wait for two seconds. */
iiDelayed = 1; /* Delay has been called: ok to initialize */
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -273,12 +272,12 @@ iiInitialize(i2eBordStrPtr pB)
if (pB->i2eValid != I2E_MAGIC)
{
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_RESET || !iiDelayed)
{
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
// In case there is a failure short of our completely reading the power-up
@@ -291,13 +290,12 @@ iiInitialize(i2eBordStrPtr pB)
for (itemp = 0; itemp < sizeof(porStr); itemp++)
{
// We expect the entire message is ready.
- if (HAS_NO_INPUT(pB))
- {
+ if (!I2_HAS_INPUT(pB)) {
pB->i2ePomSize = itemp;
- COMPLETE(pB, I2EE_PORM_SHORT);
+ I2_COMPLETE(pB, I2EE_PORM_SHORT);
}
- pB->i2ePom.c[itemp] = c = BYTE_FROM(pB);
+ pB->i2ePom.c[itemp] = c = inb(pB->i2eData);
// We check the magic numbers as soon as they are supposed to be read
// (rather than after) to minimize effect of reading something we
@@ -306,22 +304,22 @@ iiInitialize(i2eBordStrPtr pB)
(itemp == POR_2_INDEX && c != POR_MAGIC_2))
{
pB->i2ePomSize = itemp+1;
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
}
pB->i2ePomSize = itemp;
// Ensure that this was all the data...
- if (HAS_INPUT(pB))
- COMPLETE(pB, I2EE_PORM_LONG);
+ if (I2_HAS_INPUT(pB))
+ I2_COMPLETE(pB, I2EE_PORM_LONG);
// For now, we'll fail to initialize if P.O.S.T reports bad chip mapper:
// Implying we will not be able to download any code either: That's ok: the
// condition is pretty explicit.
if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER)
{
- COMPLETE(pB, I2EE_POSTERR);
+ I2_COMPLETE(pB, I2EE_POSTERR);
}
// Determine anything which must be done differently depending on the family
@@ -332,7 +330,7 @@ iiInitialize(i2eBordStrPtr pB)
pB->i2eFifoStyle = FIFO_II;
pB->i2eFifoSize = 512; // 512 bytes, always
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit
// slot, we do allow it to be done (documentation!)
@@ -354,7 +352,7 @@ iiInitialize(i2eBordStrPtr pB)
// should always be consistent for IntelliPort-II. Ditto below...
if (pB->i2ePom.e.porPorts1 != 4)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
@@ -364,7 +362,7 @@ iiInitialize(i2eBordStrPtr pB)
pB->i2eChannelMap[0] = 0xff; // Eight port
if (pB->i2ePom.e.porPorts1 != 8)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
@@ -373,7 +371,7 @@ iiInitialize(i2eBordStrPtr pB)
pB->i2eChannelMap[0] = 0x3f; // Six Port
if (pB->i2ePom.e.porPorts1 != 6)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
}
@@ -402,7 +400,7 @@ iiInitialize(i2eBordStrPtr pB)
if (itemp < 8 || itemp > 15)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
pB->i2eFifoSize = (1 << itemp);
@@ -450,26 +448,26 @@ iiInitialize(i2eBordStrPtr pB)
switch (pB->i2ePom.e.porBus & (POR_BUS_SLOT16 | POR_BUS_DIP16) )
{
case POR_BUS_SLOT16 | POR_BUS_DIP16:
- pB->i2eDataWidth16 = YES;
+ pB->i2eDataWidth16 = true;
pB->i2eMaxIrq = 15;
break;
case POR_BUS_SLOT16:
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 15;
break;
case 0:
case POR_BUS_DIP16: // In an 8-bit slot, DIP switch don't care.
default:
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 7;
break;
}
break; // POR_ID_FIIEX case
default: // Unknown type of board
- COMPLETE(pB, I2EE_BAD_FAMILY);
+ I2_COMPLETE(pB, I2EE_BAD_FAMILY);
break;
} // End the switch based on family
@@ -483,17 +481,14 @@ iiInitialize(i2eBordStrPtr pB)
{
case POR_BUS_T_ISA:
case POR_BUS_T_UNK: // If the type of bus is undeclared, assume ok.
- pB->i2eChangeIrq = YES;
- break;
case POR_BUS_T_MCA:
case POR_BUS_T_EISA:
- pB->i2eChangeIrq = NO;
break;
default:
- COMPLETE(pB, I2EE_BADBUS);
+ I2_COMPLETE(pB, I2EE_BADBUS);
}
- if (pB->i2eDataWidth16 == YES)
+ if (pB->i2eDataWidth16)
{
pB->i2eWriteBuf = iiWriteBuf16;
pB->i2eReadBuf = iiReadBuf16;
@@ -529,7 +524,7 @@ iiInitialize(i2eBordStrPtr pB)
break;
default:
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
// Initialize state information.
@@ -549,7 +544,7 @@ iiInitialize(i2eBordStrPtr pB)
// Everything is ok now, return with good status/
pB->i2eValid = I2E_MAGIC;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -658,7 +653,7 @@ ii2DelayIO(unsigned int mseconds)
while(mseconds--) {
int i = ii2DelValue;
while ( i-- ) {
- INB ( ii2Safe );
+ inb(ii2Safe);
}
}
}
@@ -709,11 +704,11 @@ iiWriteBuf16(i2eBordStrPtr pB, unsigned char *address, int count)
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- OUTSW ( pB->i2eData, address, count);
+ I2_OUTSW(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -738,11 +733,11 @@ iiWriteBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
{
/* Rudimentary sanity checking here */
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- OUTSB ( pB->i2eData, address, count );
+ I2_OUTSB(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -767,11 +762,11 @@ iiReadBuf16(i2eBordStrPtr pB, unsigned char *address, int count)
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- INSW ( pB->i2eData, address, count);
+ I2_INSW(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -796,11 +791,11 @@ iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- INSB ( pB->i2eData, address, count);
+ I2_INSB(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -820,7 +815,7 @@ iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
static unsigned short
iiReadWord16(i2eBordStrPtr pB)
{
- return (unsigned short)( INW(pB->i2eData) );
+ return inw(pB->i2eData);
}
//******************************************************************************
@@ -842,9 +837,9 @@ iiReadWord8(i2eBordStrPtr pB)
{
unsigned short urs;
- urs = INB ( pB->i2eData );
+ urs = inb(pB->i2eData);
- return ( ( INB ( pB->i2eData ) << 8 ) | urs );
+ return (inb(pB->i2eData) << 8) | urs;
}
//******************************************************************************
@@ -865,7 +860,7 @@ iiReadWord8(i2eBordStrPtr pB)
static void
iiWriteWord16(i2eBordStrPtr pB, unsigned short value)
{
- WORD_TO(pB, (int)value);
+ outw((int)value, pB->i2eData);
}
//******************************************************************************
@@ -886,8 +881,8 @@ iiWriteWord16(i2eBordStrPtr pB, unsigned short value)
static void
iiWriteWord8(i2eBordStrPtr pB, unsigned short value)
{
- BYTE_TO(pB, (char)value);
- BYTE_TO(pB, (char)(value >> 8) );
+ outb((char)value, pB->i2eData);
+ outb((char)(value >> 8), pB->i2eData);
}
//******************************************************************************
@@ -939,30 +934,30 @@ iiWaitForTxEmptyII(i2eBordStrPtr pB, int mSdelay)
// interrupts of any kind.
- WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
- OUTB(pB->i2ePointer, SEL_COMMAND);
- OUTB(pB->i2ePointer, SEL_CMD_SH);
+ write_lock_irqsave(&Dl_spinlock, flags);
+ outb(SEL_COMMAND, pB->i2ePointer);
+ outb(SEL_CMD_SH, pB->i2ePointer);
- itemp = INB(pB->i2eStatus);
+ itemp = inb(pB->i2eStatus);
- OUTB(pB->i2ePointer, SEL_COMMAND);
- OUTB(pB->i2ePointer, SEL_CMD_UNSH);
+ outb(SEL_COMMAND, pB->i2ePointer);
+ outb(SEL_CMD_UNSH, pB->i2ePointer);
if (itemp & ST_IN_EMPTY)
{
- UPDATE_FIFO_ROOM(pB);
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
- COMPLETE(pB, I2EE_GOOD);
+ I2_UPDATE_FIFO_ROOM(pB);
+ write_unlock_irqrestore(&Dl_spinlock, flags);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ write_unlock_irqrestore(&Dl_spinlock, flags);
if (mSdelay-- == 0)
break;
iiDelay(pB, 1); /* 1 mS granularity on checking condition */
}
- COMPLETE(pB, I2EE_TXE_TIME);
+ I2_COMPLETE(pB, I2EE_TXE_TIME);
}
//******************************************************************************
@@ -1002,21 +997,21 @@ iiWaitForTxEmptyIIEX(i2eBordStrPtr pB, int mSdelay)
// you will generally not want to service interrupts or in any way
// disrupt the assumptions implicit in the larger context.
- WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
+ write_lock_irqsave(&Dl_spinlock, flags);
- if (INB(pB->i2eStatus) & STE_OUT_MT) {
- UPDATE_FIFO_ROOM(pB);
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
- COMPLETE(pB, I2EE_GOOD);
+ if (inb(pB->i2eStatus) & STE_OUT_MT) {
+ I2_UPDATE_FIFO_ROOM(pB);
+ write_unlock_irqrestore(&Dl_spinlock, flags);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ write_unlock_irqrestore(&Dl_spinlock, flags);
if (mSdelay-- == 0)
break;
iiDelay(pB, 1); // 1 mS granularity on checking condition
}
- COMPLETE(pB, I2EE_TXE_TIME);
+ I2_COMPLETE(pB, I2EE_TXE_TIME);
}
//******************************************************************************
@@ -1038,8 +1033,8 @@ static int
iiTxMailEmptyII(i2eBordStrPtr pB)
{
int port = pB->i2ePointer;
- OUTB ( port, SEL_OUTMAIL );
- return ( INB(port) == 0 );
+ outb(SEL_OUTMAIL, port);
+ return inb(port) == 0;
}
//******************************************************************************
@@ -1060,7 +1055,7 @@ iiTxMailEmptyII(i2eBordStrPtr pB)
static int
iiTxMailEmptyIIEX(i2eBordStrPtr pB)
{
- return !(INB(pB->i2eStatus) & STE_OUT_MAIL);
+ return !(inb(pB->i2eStatus) & STE_OUT_MAIL);
}
//******************************************************************************
@@ -1084,10 +1079,10 @@ iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail)
{
int port = pB->i2ePointer;
- OUTB(port, SEL_OUTMAIL);
- if (INB(port) == 0) {
- OUTB(port, SEL_OUTMAIL);
- OUTB(port, mail);
+ outb(SEL_OUTMAIL, port);
+ if (inb(port) == 0) {
+ outb(SEL_OUTMAIL, port);
+ outb(mail, port);
return 1;
}
return 0;
@@ -1112,10 +1107,9 @@ iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail)
static int
iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail)
{
- if(INB(pB->i2eStatus) & STE_OUT_MAIL) {
+ if (inb(pB->i2eStatus) & STE_OUT_MAIL)
return 0;
- }
- OUTB(pB->i2eXMail, mail);
+ outb(mail, pB->i2eXMail);
return 1;
}
@@ -1136,9 +1130,9 @@ iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail)
static unsigned short
iiGetMailII(i2eBordStrPtr pB)
{
- if (HAS_MAIL(pB)) {
- OUTB(pB->i2ePointer, SEL_INMAIL);
- return INB(pB->i2ePointer);
+ if (I2_HAS_MAIL(pB)) {
+ outb(SEL_INMAIL, pB->i2ePointer);
+ return inb(pB->i2ePointer);
} else {
return NO_MAIL_HERE;
}
@@ -1161,11 +1155,10 @@ iiGetMailII(i2eBordStrPtr pB)
static unsigned short
iiGetMailIIEX(i2eBordStrPtr pB)
{
- if (HAS_MAIL(pB)) {
- return INB(pB->i2eXMail);
- } else {
+ if (I2_HAS_MAIL(pB))
+ return inb(pB->i2eXMail);
+ else
return NO_MAIL_HERE;
- }
}
//******************************************************************************
@@ -1184,8 +1177,8 @@ iiGetMailIIEX(i2eBordStrPtr pB)
static void
iiEnableMailIrqII(i2eBordStrPtr pB)
{
- OUTB(pB->i2ePointer, SEL_MASK);
- OUTB(pB->i2ePointer, ST_IN_MAIL);
+ outb(SEL_MASK, pB->i2ePointer);
+ outb(ST_IN_MAIL, pB->i2ePointer);
}
//******************************************************************************
@@ -1204,7 +1197,7 @@ iiEnableMailIrqII(i2eBordStrPtr pB)
static void
iiEnableMailIrqIIEX(i2eBordStrPtr pB)
{
- OUTB(pB->i2eXMask, MX_IN_MAIL);
+ outb(MX_IN_MAIL, pB->i2eXMask);
}
//******************************************************************************
@@ -1223,8 +1216,8 @@ iiEnableMailIrqIIEX(i2eBordStrPtr pB)
static void
iiWriteMaskII(i2eBordStrPtr pB, unsigned char value)
{
- OUTB(pB->i2ePointer, SEL_MASK);
- OUTB(pB->i2ePointer, value);
+ outb(SEL_MASK, pB->i2ePointer);
+ outb(value, pB->i2ePointer);
}
//******************************************************************************
@@ -1243,7 +1236,7 @@ iiWriteMaskII(i2eBordStrPtr pB, unsigned char value)
static void
iiWriteMaskIIEX(i2eBordStrPtr pB, unsigned char value)
{
- OUTB(pB->i2eXMask, value);
+ outb(value, pB->i2eXMask);
}
//******************************************************************************
@@ -1354,9 +1347,8 @@ iiDownloadBlock ( i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard)
// immediately and be harmless, though not strictly necessary.
itemp = MAX_DLOAD_ACK_TIME/10;
while (--itemp) {
- if (HAS_INPUT(pB)) {
- switch(BYTE_FROM(pB))
- {
+ if (I2_HAS_INPUT(pB)) {
+ switch (inb(pB->i2eData)) {
case LOADWARE_OK:
pB->i2eState =
isStandard ? II_STATE_STDLOADED :II_STATE_LOADED;
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index 433305062fb..c88a64e527a 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -185,10 +185,6 @@ typedef struct _i2eBordStr
// The highest allowable IRQ, based on the
// slot size.
- unsigned char i2eChangeIrq;
- // Whether tis valid to change IRQ's
- // ISA = ok, EISA, MicroChannel, no
-
// Accelerators for various addresses on the board
int i2eBase; // I/O Address of the Board
int i2eData; // From here data transfers happen
@@ -431,12 +427,6 @@ typedef struct _i2eBordStr
// Manifests for i2eBordStr:
//-------------------------------------------
-#define YES 1
-#define NO 0
-
-#define NULLFUNC (void (*)(void))0
-#define NULLPTR (void *)0
-
typedef void (*delayFunc_t)(unsigned int);
// i2eValid
@@ -494,8 +484,8 @@ typedef void (*delayFunc_t)(unsigned int);
// i2eUsingIrq
//
-#define IRQ_UNDEFINED 0x1352 // No valid irq (or polling = 0) can ever
- // promote to this!
+#define I2_IRQ_UNDEFINED 0x1352 /* No valid irq (or polling = 0) can
+ * ever promote to this! */
//------------------------------------------
// Handy Macros for i2ellis.c and others
// Note these are common to -II and -IIEX
@@ -504,41 +494,14 @@ typedef void (*delayFunc_t)(unsigned int);
// Given a pointer to the board structure, does the input FIFO have any data or
// not?
//
-#define HAS_INPUT(pB) !(INB(pB->i2eStatus) & ST_IN_EMPTY)
-#define HAS_NO_INPUT(pB) (INB(pB->i2eStatus) & ST_IN_EMPTY)
-
-// Given a pointer to board structure, read a byte or word from the fifo
-//
-#define BYTE_FROM(pB) (unsigned char)INB(pB->i2eData)
-#define WORD_FROM(pB) (unsigned short)INW(pB->i2eData)
-
-// Given a pointer to board structure, is there room for any data to be written
-// to the data fifo?
-//
-#define HAS_OUTROOM(pB) !(INB(pB->i2eStatus) & ST_OUT_FULL)
-#define HAS_NO_OUTROOM(pB) (INB(pB->i2eStatus) & ST_OUT_FULL)
-
-// Given a pointer to board structure, write a single byte to the fifo
-// structure. Note that for 16-bit interfaces, the high order byte is undefined
-// and unknown.
-//
-#define BYTE_TO(pB, c) OUTB(pB->i2eData,(c))
-
-// Write a word to the fifo structure. For 8-bit interfaces, this may have
-// unknown results.
-//
-#define WORD_TO(pB, c) OUTW(pB->i2eData,(c))
+#define I2_HAS_INPUT(pB) !(inb(pB->i2eStatus) & ST_IN_EMPTY)
// Given a pointer to the board structure, is there anything in the incoming
// mailbox?
//
-#define HAS_MAIL(pB) (INB(pB->i2eStatus) & ST_IN_MAIL)
+#define I2_HAS_MAIL(pB) (inb(pB->i2eStatus) & ST_IN_MAIL)
-#define UPDATE_FIFO_ROOM(pB) (pB)->i2eFifoRemains=(pB)->i2eFifoSize
-
-// Handy macro to round up a number (like the buffer write and read routines do)
-//
-#define ROUNDUP(number) (((number)+1) & (~1))
+#define I2_UPDATE_FIFO_ROOM(pB) ((pB)->i2eFifoRemains = (pB)->i2eFifoSize)
//------------------------------------------
// Function Declarations for i2ellis.c
@@ -593,20 +556,11 @@ static int iiDownloadBlock(i2eBordStrPtr, loadHdrStrPtr, int);
//
static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int);
-// Called indirectly always. Needed externally so the routine might be
-// SPECIFIED as an argument to iiReset()
-//
-//static void ii2DelayIO(unsigned int); // N-millisecond delay using
- //hardware spin
-//static void ii2DelayTimer(unsigned int); // N-millisecond delay using Linux
- //timer
-
// Many functions defined here return True if good, False otherwise, with an
// error code in i2eError field. Here is a handy macro for setting the error
// code and returning.
//
-#define COMPLETE(pB,code) \
- do { \
+#define I2_COMPLETE(pB,code) do { \
pB->i2eError = code; \
return (code == I2EE_GOOD);\
} while (0)
diff --git a/drivers/char/ip2/i2hw.h b/drivers/char/ip2/i2hw.h
index 15fe04e748f..8aa6e7ab8d5 100644
--- a/drivers/char/ip2/i2hw.h
+++ b/drivers/char/ip2/i2hw.h
@@ -129,7 +129,6 @@ registers, use byte operations only.
//------------------------------------------------
//
#include "ip2types.h"
-#include "i2os.h" /* For any o.s., compiler, or host-related issues */
//-------------------------------------------------------------------------
// Manifests for the I/O map:
@@ -644,5 +643,10 @@ typedef union _loadHdrStr
#define ABS_BIGGEST_BOX 16 // Absolute the most ports per box
#define ABS_MOST_PORTS (ABS_MAX_BOXES * ABS_BIGGEST_BOX)
+#define I2_OUTSW(port, addr, count) outsw((port), (addr), (((count)+1)/2))
+#define I2_OUTSB(port, addr, count) outsb((port), (addr), (((count)+1))&-2)
+#define I2_INSW(port, addr, count) insw((port), (addr), (((count)+1)/2))
+#define I2_INSB(port, addr, count) insb((port), (addr), (((count)+1))&-2)
+
#endif // I2HW_H
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 9c25320121e..938879cc7bc 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -227,17 +227,17 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
i2ChanStrPtr *ppCh;
if (pB->i2eValid != I2E_MAGIC) {
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_STDLOADED) {
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
- LOCK_INIT(&pB->read_fifo_spinlock);
- LOCK_INIT(&pB->write_fifo_spinlock);
- LOCK_INIT(&pB->Dbuf_spinlock);
- LOCK_INIT(&pB->Bbuf_spinlock);
- LOCK_INIT(&pB->Fbuf_spinlock);
+ rwlock_init(&pB->read_fifo_spinlock);
+ rwlock_init(&pB->write_fifo_spinlock);
+ rwlock_init(&pB->Dbuf_spinlock);
+ rwlock_init(&pB->Bbuf_spinlock);
+ rwlock_init(&pB->Fbuf_spinlock);
// NO LOCK needed yet - this is init
@@ -259,10 +259,10 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) {
continue;
}
- LOCK_INIT(&pCh->Ibuf_spinlock);
- LOCK_INIT(&pCh->Obuf_spinlock);
- LOCK_INIT(&pCh->Cbuf_spinlock);
- LOCK_INIT(&pCh->Pbuf_spinlock);
+ rwlock_init(&pCh->Ibuf_spinlock);
+ rwlock_init(&pCh->Obuf_spinlock);
+ rwlock_init(&pCh->Cbuf_spinlock);
+ rwlock_init(&pCh->Pbuf_spinlock);
// NO LOCK needed yet - this is init
// Set up validity flag according to support level
if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) {
@@ -347,7 +347,7 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
}
// No need to check for wrap here; this is initialization.
pB->i2Fbuf_stuff = stuffIndex;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
@@ -374,7 +374,7 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
case NEED_INLINE:
- WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Dbuf_spinlock, flags);
if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip)
{
queueIndex = pB->i2Dbuf_strip;
@@ -386,12 +386,12 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
pB->i2Dbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_INLINE;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Dbuf_spinlock, flags);
break;
case NEED_BYPASS:
- WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Bbuf_spinlock, flags);
if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip)
{
queueIndex = pB->i2Bbuf_strip;
@@ -403,12 +403,12 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
pB->i2Bbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_BYPASS;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Bbuf_spinlock, flags);
break;
case NEED_FLOW:
- WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Fbuf_spinlock, flags);
if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip)
{
queueIndex = pB->i2Fbuf_strip;
@@ -420,7 +420,7 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
pB->i2Fbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_FLOW;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Fbuf_spinlock, flags);
break;
default:
printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type);
@@ -453,7 +453,7 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
case NEED_INLINE:
- WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Dbuf_spinlock, flags);
if ( !(pCh->channelNeeds & NEED_INLINE) )
{
pCh->channelNeeds |= NEED_INLINE;
@@ -463,12 +463,12 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
queueIndex = 0;
pB->i2Dbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Dbuf_spinlock, flags);
break;
case NEED_BYPASS:
- WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Bbuf_spinlock, flags);
if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS))
{
pCh->channelNeeds |= NEED_BYPASS;
@@ -478,12 +478,12 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
queueIndex = 0;
pB->i2Bbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Bbuf_spinlock, flags);
break;
case NEED_FLOW:
- WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Fbuf_spinlock, flags);
if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW))
{
pCh->channelNeeds |= NEED_FLOW;
@@ -493,7 +493,7 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
queueIndex = 0;
pB->i2Fbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Fbuf_spinlock, flags);
break;
case NEED_CREDIT:
@@ -562,9 +562,8 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
pB = pCh->pMyBord;
// Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT
- if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) {
+ if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == I2_IRQ_UNDEFINED)
return -2;
- }
// If the board has gone fatal, return bad, and also hit the trap routine if
// it exists.
if (pB->i2eFatal) {
@@ -620,13 +619,13 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
switch(type) {
case PTYPE_INLINE:
lock_var_p = &pCh->Obuf_spinlock;
- WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ write_lock_irqsave(lock_var_p, flags);
stuffIndex = pCh->Obuf_stuff;
bufroom = pCh->Obuf_strip - stuffIndex;
break;
case PTYPE_BYPASS:
lock_var_p = &pCh->Cbuf_spinlock;
- WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ write_lock_irqsave(lock_var_p, flags);
stuffIndex = pCh->Cbuf_stuff;
bufroom = pCh->Cbuf_strip - stuffIndex;
break;
@@ -645,7 +644,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
break; /* from for()- Enough room: goto proceed */
}
ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize);
- WRITE_UNLOCK_IRQRESTORE(lock_var_p, flags);
+ write_unlock_irqrestore(lock_var_p, flags);
} else
ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize);
@@ -747,7 +746,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
{
case PTYPE_INLINE:
pCh->Obuf_stuff = stuffIndex; // Store buffer pointer
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
pB->debugInlineQueued++;
// Add the channel pointer to list of channels needing service (first
@@ -757,7 +756,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
case PTYPE_BYPASS:
pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer
- WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags);
pB->debugBypassQueued++;
// Add the channel pointer to list of channels needing service (first
@@ -840,7 +839,7 @@ i2Input(i2ChanStrPtr pCh)
count = -1;
goto i2Input_exit;
}
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, flags);
// initialize some accelerators and private copies
stripIndex = pCh->Ibuf_strip;
@@ -850,7 +849,7 @@ i2Input(i2ChanStrPtr pCh)
// If buffer is empty or requested data count was 0, (trivial case) return
// without any further thought.
if ( count == 0 ) {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
goto i2Input_exit;
}
// Adjust for buffer wrap
@@ -891,10 +890,10 @@ i2Input(i2ChanStrPtr pCh)
if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) {
pCh->sinceLastFlow -= pCh->whenSendFlow;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
} else {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
i2Input_exit:
@@ -926,7 +925,7 @@ i2InputFlush(i2ChanStrPtr pCh)
ip2trace (CHANN, ITRC_INPUT, 10, 0);
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, flags);
count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
// Adjust for buffer wrap
@@ -947,10 +946,10 @@ i2InputFlush(i2ChanStrPtr pCh)
if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow )
{
pCh->sinceLastFlow -= pCh->whenSendFlow;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
} else {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
ip2trace (CHANN, ITRC_INPUT, 19, 1, count);
@@ -979,9 +978,9 @@ i2InputAvailable(i2ChanStrPtr pCh)
// initialize some accelerators and private copies
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
// Adjust for buffer wrap
if (count < 0)
@@ -1045,9 +1044,9 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
while ( count > 0 ) {
// How much room in output buffer is there?
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if (amountToMove < 0) {
amountToMove += OBUF_SIZE;
}
@@ -1075,7 +1074,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) )
&& amountToMove > 0 )
{
- WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Obuf_spinlock, flags);
stuffIndex = pCh->Obuf_stuff;
// Had room to move some data: don't know whether the block size,
@@ -1102,7 +1101,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
}
pCh->Obuf_stuff = stuffIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex );
@@ -1352,9 +1351,9 @@ i2OutputFree(i2ChanStrPtr pCh)
if ( !i2Validate ( pCh ) ) {
return -1;
}
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if (amountToMove < 0) {
amountToMove += OBUF_SIZE;
@@ -1464,11 +1463,11 @@ i2StripFifo(i2eBordStrPtr pB)
// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 );
- while (HAS_INPUT(pB)) {
+ while (I2_HAS_INPUT(pB)) {
// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 );
// Process packet from fifo a one atomic unit
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, bflags);
// The first word (or two bytes) will have channel number and type of
// packet, possibly other information
@@ -1490,7 +1489,8 @@ i2StripFifo(i2eBordStrPtr pB)
// sick!
if ( ((unsigned int)count) > IBUF_SIZE ) {
pB->i2eFatal = 2;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
return; /* Bail out ASAP */
}
// Channel is illegally big ?
@@ -1498,7 +1498,8 @@ i2StripFifo(i2eBordStrPtr pB)
(NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])))
{
iiReadBuf(pB, junkBuffer, count);
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
break; /* From switch: ready for next packet */
}
@@ -1512,14 +1513,15 @@ i2StripFifo(i2eBordStrPtr pB)
if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY)
{
pCh->hotKeyIn = iiReadWord(pB) & 0xff;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK);
break; /* From the switch: ready for next packet */
}
// Normal data! We crudely assume there is room for the data in our
// buffer because the board wouldn't have exceeded his credit limit.
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, cflags);
// We have 2 locks now
stuffIndex = pCh->Ibuf_stuff;
amountToRead = IBUF_SIZE - stuffIndex;
@@ -1562,8 +1564,9 @@ i2StripFifo(i2eBordStrPtr pB)
// Update stuff index
pCh->Ibuf_stuff = stuffIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags);
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, cflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
#ifdef USE_IQ
schedule_work(&pCh->tqueue_input);
@@ -1585,7 +1588,8 @@ i2StripFifo(i2eBordStrPtr pB)
iiReadBuf(pB, cmdBuffer, count);
// We can release early with buffer grab
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
pc = cmdBuffer;
pcLimit = &(cmdBuffer[count]);
@@ -1830,12 +1834,12 @@ i2StripFifo(i2eBordStrPtr pB)
default: // Neither packet? should be impossible
ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1,
PTYPE_OF(pB->i2eLeadoffWord) );
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
bflags);
break;
} // End of switch on type of packets
- } //while(board HAS_INPUT)
+ } /*while(board I2_HAS_INPUT)*/
ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 );
@@ -1858,7 +1862,7 @@ i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve)
{
int rc = 0;
unsigned long flags;
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
if (!pB->i2eWaitingForEmptyFifo) {
if (pB->i2eFifoRemains > (count+reserve)) {
pB->i2eFifoRemains -= count;
@@ -1867,7 +1871,7 @@ i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve)
rc = count;
}
}
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
return rc;
}
//******************************************************************************
@@ -1898,7 +1902,7 @@ i2StuffFifoBypass(i2eBordStrPtr pB)
while ( --bailout && notClogged &&
(NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS))))
{
- WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Cbuf_spinlock, flags);
stripIndex = pCh->Cbuf_strip;
// as long as there are packets for this channel...
@@ -1906,7 +1910,7 @@ i2StuffFifoBypass(i2eBordStrPtr pB)
while (stripIndex != pCh->Cbuf_stuff) {
pRemove = &(pCh->Cbuf[stripIndex]);
packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader);
- paddedSize = ROUNDUP(packetSize);
+ paddedSize = roundup(packetSize, 2);
if (paddedSize > 0) {
if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) {
@@ -1930,7 +1934,7 @@ WriteDBGBuf("BYPS", pRemove, paddedSize);
// Done with this channel. Move to next, removing this one from
// the queue of channels if we cleaned it out (i.e., didn't get clogged.
pCh->Cbuf_strip = stripIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags);
} // Either clogged or finished all the work
#ifdef IP2DEBUG_TRACE
@@ -1954,7 +1958,7 @@ static inline void
i2StuffFifoFlow(i2eBordStrPtr pB)
{
i2ChanStrPtr pCh;
- unsigned short paddedSize = ROUNDUP(sizeof(flowIn));
+ unsigned short paddedSize = roundup(sizeof(flowIn), 2);
ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2,
pB->i2eFifoRemains, paddedSize );
@@ -2010,7 +2014,7 @@ i2StuffFifoInline(i2eBordStrPtr pB)
while ( --bailout && notClogged &&
(NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) )
{
- WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Obuf_spinlock, flags);
stripIndex = pCh->Obuf_strip;
ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff );
@@ -2031,7 +2035,7 @@ i2StuffFifoInline(i2eBordStrPtr pB)
packetSize = flowsize + sizeof(i2CmdHeader);
}
flowsize = CREDIT_USAGE(flowsize);
- paddedSize = ROUNDUP(packetSize);
+ paddedSize = roundup(packetSize, 2);
ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize );
@@ -2086,7 +2090,7 @@ WriteDBGBuf("DATA", pRemove, paddedSize);
// Done with this channel. Move to next, removing this one from the
// queue of channels if we cleaned it out (i.e., didn't get clogged.
pCh->Obuf_strip = stripIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if ( notClogged )
{
@@ -2190,10 +2194,11 @@ i2ServiceBoard ( i2eBordStrPtr pB )
if (inmail & MB_OUT_STRIPPED) {
pB->i2eFifoOutInts++;
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
pB->i2eFifoRemains = pB->i2eFifoSize;
pB->i2eWaitingForEmptyFifo = 0;
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock,
+ flags);
ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains );
diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h
deleted file mode 100644
index eff9b542d69..00000000000
--- a/drivers/char/ip2/i2os.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
-*
-* (c) 1999 by Computone Corporation
-*
-********************************************************************************
-*
-*
-* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
-* serial I/O controllers.
-*
-* DESCRIPTION: Defines, definitions and includes which are heavily dependent
-* on O/S, host, compiler, etc. This file is tailored for:
-* Linux v2.0.0 and later
-* Gnu gcc c2.7.2
-* 80x86 architecture
-*
-*******************************************************************************/
-
-#ifndef I2OS_H /* To prevent multiple includes */
-#define I2OS_H 1
-
-//-------------------------------------------------
-// Required Includes
-//-------------------------------------------------
-
-#include "ip2types.h"
-#include <asm/io.h> /* For inb, etc */
-
-//------------------------------------
-// Defines for I/O instructions:
-//------------------------------------
-
-#define INB(port) inb(port)
-#define OUTB(port,value) outb((value),(port))
-#define INW(port) inw(port)
-#define OUTW(port,value) outw((value),(port))
-#define OUTSW(port,addr,count) outsw((port),(addr),(((count)+1)/2))
-#define OUTSB(port,addr,count) outsb((port),(addr),(((count)+1))&-2)
-#define INSW(port,addr,count) insw((port),(addr),(((count)+1)/2))
-#define INSB(port,addr,count) insb((port),(addr),(((count)+1))&-2)
-
-//--------------------------------------------
-// Interrupt control
-//--------------------------------------------
-
-#define LOCK_INIT(a) rwlock_init(a)
-
-#define SAVE_AND_DISABLE_INTS(a,b) { \
- /* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- spin_lock_irqsave(a,b); \
-}
-
-#define RESTORE_INTS(a,b) { \
- /* printk("rel_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- spin_unlock_irqrestore(a,b); \
-}
-
-#define READ_LOCK_IRQSAVE(a,b) { \
- /* printk("get_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- read_lock_irqsave(a,b); \
-}
-
-#define READ_UNLOCK_IRQRESTORE(a,b) { \
- /* printk("rel_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- read_unlock_irqrestore(a,b); \
-}
-
-#define WRITE_LOCK_IRQSAVE(a,b) { \
- /* printk("get_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- write_lock_irqsave(a,b); \
-}
-
-#define WRITE_UNLOCK_IRQRESTORE(a,b) { \
- /* printk("rel_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- write_unlock_irqrestore(a,b); \
-}
-
-
-//------------------------------------------------------------------------------
-// Hardware-delay loop
-//
-// Probably used in only one place (see i2ellis.c) but this helps keep things
-// together. Note we have unwound the IN instructions. On machines with a
-// reasonable cache, the eight instructions (1 byte each) should fit in cache
-// nicely, and on un-cached machines, the code-fetch would tend not to dominate.
-// Note that cx is shifted so that "count" still reflects the total number of
-// iterations assuming no unwinding.
-//------------------------------------------------------------------------------
-
-//#define DELAY1MS(port,count,label)
-
-//------------------------------------------------------------------------------
-// Macros to switch to a new stack, saving stack pointers, and to restore the
-// old stack (Used, for example, in i2lib.c) "heap" is the address of some
-// buffer which will become the new stack (working down from highest address).
-// The two words at the two lowest addresses in this stack are for storing the
-// SS and SP.
-//------------------------------------------------------------------------------
-
-//#define TO_NEW_STACK(heap,size)
-//#define TO_OLD_STACK(heap)
-
-//------------------------------------------------------------------------------
-// Macros to save the original IRQ vectors and masks, and to patch in new ones.
-//------------------------------------------------------------------------------
-
-//#define SAVE_IRQ_MASKS(dest)
-//#define WRITE_IRQ_MASKS(src)
-//#define SAVE_IRQ_VECTOR(value,dest)
-//#define WRITE_IRQ_VECTOR(value,src)
-
-//------------------------------------------------------------------------------
-// Macro to copy data from one far pointer to another.
-//------------------------------------------------------------------------------
-
-#define I2_MOVE_DATA(fpSource,fpDest,count) memmove(fpDest,fpSource,count);
-
-//------------------------------------------------------------------------------
-// Macros to issue eoi's to host interrupt control (IBM AT 8259-style).
-//------------------------------------------------------------------------------
-
-//#define MASTER_EOI
-//#define SLAVE_EOI
-
-#endif /* I2OS_H */
-
-
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 0a61856c631..70957acaa96 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -169,7 +169,7 @@ static int Fip_firmware_size;
static int ip2_open(PTTY, struct file *);
static void ip2_close(PTTY, struct file *);
static int ip2_write(PTTY, const unsigned char *, int);
-static void ip2_putchar(PTTY, unsigned char);
+static int ip2_putchar(PTTY, unsigned char);
static void ip2_flush_chars(PTTY);
static int ip2_write_room(PTTY);
static int ip2_chars_in_buf(PTTY);
@@ -355,14 +355,15 @@ have_requested_irq( char irq )
/* the driver initialisation function and returns what it returns. */
/******************************************************************************/
#ifdef MODULE
-int
-init_module(void)
+static int __init
+ip2_init_module(void)
{
#ifdef IP2DEBUG_INIT
printk (KERN_DEBUG "Loading module ...\n" );
#endif
return 0;
}
+module_init(ip2_init_module);
#endif /* MODULE */
/******************************************************************************/
@@ -381,8 +382,8 @@ init_module(void)
/* driver should be returned since it may be unloaded from memory. */
/******************************************************************************/
#ifdef MODULE
-void
-cleanup_module(void)
+void __exit
+ip2_cleanup_module(void)
{
int err;
int i;
@@ -452,6 +453,7 @@ cleanup_module(void)
printk (KERN_DEBUG "IP2 Unloaded\n" );
#endif
}
+module_exit(ip2_cleanup_module);
#endif /* MODULE */
static const struct tty_operations ip2_ops = {
@@ -1050,9 +1052,9 @@ set_irq( int boardnum, int boardIrq )
* Write to FIFO; don't bother to adjust fifo capacity for this, since
* board will respond almost immediately after SendMail hit.
*/
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 4);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
pB->i2eUsingIrq = boardIrq;
pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
@@ -1070,9 +1072,9 @@ set_irq( int boardnum, int boardIrq )
(CMD_OF(tempCommand))[4] = 64; // chars
(CMD_OF(tempCommand))[5] = 87; // HW_TEST
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 8);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
CHANNEL_OF(tempCommand) = 0;
PTYPE_OF(tempCommand) = PTYPE_BYPASS;
@@ -1087,9 +1089,9 @@ set_irq( int boardnum, int boardIrq )
CMD_COUNT_OF(tempCommand) = 2;
(CMD_OF(tempCommand))[0] = 44; /* get ping */
(CMD_OF(tempCommand))[1] = 200; /* 200 ms */
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 4);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
#endif
iiEnableMailIrq(pB);
@@ -1268,12 +1270,12 @@ static void do_input(struct work_struct *work)
// Data input
if ( pCh->pTTY != NULL ) {
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2Input( pCh );
} else
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
} else {
ip2trace(CHANN, ITRC_INPUT, 22, 0 );
@@ -1614,10 +1616,8 @@ ip2_close( PTTY tty, struct file *pFile )
serviceOutgoingFifo ( pCh->pMyBord );
- if ( tty->driver->flush_buffer )
- tty->driver->flush_buffer(tty);
- if ( tty->ldisc.flush_buffer )
- tty->ldisc.flush_buffer(tty);
+ tty_ldisc_flush(tty);
+ tty_driver_flush_buffer(tty);
tty->closing = 0;
pCh->pTTY = NULL;
@@ -1717,9 +1717,9 @@ ip2_write( PTTY tty, const unsigned char *pData, int count)
ip2_flush_chars( tty );
/* This is the actual move bit. Make sure it does what we need!!!!! */
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
bytesSent = i2Output( pCh, pData, count);
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
@@ -1736,7 +1736,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count)
/* */
/* */
/******************************************************************************/
-static void
+static int
ip2_putchar( PTTY tty, unsigned char ch )
{
i2ChanStrPtr pCh = tty->driver_data;
@@ -1744,13 +1744,14 @@ ip2_putchar( PTTY tty, unsigned char ch )
// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2_flush_chars( tty );
} else
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
+ return 1;
// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
}
@@ -1770,7 +1771,7 @@ ip2_flush_chars( PTTY tty )
i2ChanStrPtr pCh = tty->driver_data;
unsigned long flags;
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
if ( pCh->Pbuf_stuff ) {
// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
@@ -1784,7 +1785,7 @@ ip2_flush_chars( PTTY tty )
}
pCh->Pbuf_stuff -= strip;
}
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
}
/******************************************************************************/
@@ -1802,9 +1803,9 @@ ip2_write_room ( PTTY tty )
i2ChanStrPtr pCh = tty->driver_data;
unsigned long flags;
- READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
- READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
@@ -1834,12 +1835,12 @@ ip2_chars_in_buf ( PTTY tty )
pCh->Obuf_char_count + pCh->Pbuf_stuff,
pCh->Obuf_char_count, pCh->Pbuf_stuff );
#endif
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
rc = pCh->Obuf_char_count;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
- READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
+ read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
rc += pCh->Pbuf_stuff;
- READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
return rc;
}
@@ -1863,9 +1864,9 @@ ip2_flush_buffer( PTTY tty )
#ifdef IP2DEBUG_WRITE
printk (KERN_DEBUG "IP2: flush buffer\n" );
#endif
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
pCh->Pbuf_stuff = 0;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
i2FlushOutput( pCh );
ip2_owake(tty);
@@ -1951,15 +1952,15 @@ ip2_unthrottle ( PTTY tty )
pCh->throttled = 0;
i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
serviceOutgoingFifo( pCh->pMyBord );
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
#ifdef IP2DEBUG_READ
printk (KERN_DEBUG "i2Input called from unthrottle\n" );
#endif
i2Input( pCh );
} else
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
static void
@@ -2202,9 +2203,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
* for masking). Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cprev = pCh->icount; /* note the counters on entry */
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
init_waitqueue_entry(&wait, current);
@@ -2224,9 +2225,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
rc = -ERESTARTSYS;
break;
}
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount; /* atomic copy */
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
rc = -EIO; /* no change => rc */
@@ -2264,9 +2265,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
case TIOCGICOUNT:
ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
p_cuser = argp;
rc = put_user(cnow.cts, &p_cuser->cts);
rc = put_user(cnow.dsr, &p_cuser->dsr);
@@ -2872,7 +2873,7 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
case 65: /* Board - ip2stat */
if ( pB ) {
rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
- rc = put_user(INB(pB->i2eStatus),
+ rc = put_user(inb(pB->i2eStatus),
(ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
} else {
rc = -ENODEV;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index eba2883b630..4f3cefa8eb0 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -126,8 +126,8 @@
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <linux/pci.h>
@@ -189,7 +189,7 @@ struct isi_board {
unsigned short status;
unsigned short port_status; /* each bit for each port */
unsigned short shift_count;
- struct isi_port * ports;
+ struct isi_port *ports;
signed char count;
spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
unsigned long flags;
@@ -205,11 +205,11 @@ struct isi_port {
u16 channel;
u16 status;
u16 closing_wait;
- struct isi_board * card;
- struct tty_struct * tty;
+ struct isi_board *card;
+ struct tty_struct *tty;
wait_queue_head_t close_wait;
wait_queue_head_t open_wait;
- unsigned char * xmit_buf;
+ unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
@@ -405,7 +405,7 @@ static void isicom_tx(unsigned long _data)
/* find next active board */
card = (prev_card + 1) & 0x0003;
- while(count-- > 0) {
+ while (count-- > 0) {
if (isi_card[card].status & BOARD_ACTIVE)
break;
card = (card + 1) & 0x0003;
@@ -428,7 +428,7 @@ static void isicom_tx(unsigned long _data)
if (retries >= 100)
goto unlock;
- for (;count > 0;count--, port++) {
+ for (; count > 0; count--, port++) {
/* port not active or tx disabled to force flow control */
if (!(port->flags & ASYNC_INITIALIZED) ||
!(port->status & ISI_TXOK))
@@ -471,9 +471,10 @@ static void isicom_tx(unsigned long _data)
break;
}
}
- if (cnt <= 0) break;
+ if (cnt <= 0)
+ break;
word_count = cnt >> 1;
- outsw(base, port->xmit_buf+port->xmit_tail,word_count);
+ outsw(base, port->xmit_buf+port->xmit_tail, word_count);
port->xmit_tail = (port->xmit_tail
+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
txcount -= (word_count << 1);
@@ -556,7 +557,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
tty = port->tty;
if (tty == NULL) {
word_count = byte_count >> 1;
- while(byte_count > 1) {
+ while (byte_count > 1) {
inw(base);
byte_count -= 2;
}
@@ -569,7 +570,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (header & 0x8000) { /* Status Packet */
header = inw(base);
- switch(header & 0xff) {
+ switch (header & 0xff) {
case 0: /* Change in EIA signals */
if (port->flags & ASYNC_CHECK_CD) {
if (port->status & ISI_DCD) {
@@ -656,7 +657,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (byte_count > 0) {
pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
"bytes...\n", base, channel + 1);
- while(byte_count > 0) { /* drain out unread xtra data */
+ /* drain out unread xtra data */
+ while (byte_count > 0) {
inw(base);
byte_count -= 2;
}
@@ -679,8 +681,11 @@ static void isicom_config_port(struct isi_port *port)
shift_count = card->shift_count;
unsigned char flow_ctrl;
- if (!(tty = port->tty) || !tty->termios)
+ tty = port->tty;
+
+ if (tty == NULL)
return;
+ /* FIXME: Switch to new tty baud API */
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
baud &= ~CBAUDEX;
@@ -706,7 +711,7 @@ static void isicom_config_port(struct isi_port *port)
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
baud++; /* 57.6 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- baud +=2; /* 115 Kbps */
+ baud += 2; /* 115 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
baud += 3; /* 230 kbps*/
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
@@ -716,15 +721,14 @@ static void isicom_config_port(struct isi_port *port)
/* hang up */
drop_dtr(port);
return;
- }
- else
+ } else
raise_dtr(port);
if (WaitTillCardIsFree(base) == 0) {
- outw(0x8000 | (channel << shift_count) |0x03, base);
+ outw(0x8000 | (channel << shift_count) | 0x03, base);
outw(linuxb_to_isib[baud] << 8 | 0x03, base);
channel_setup = 0;
- switch(C_CSIZE(tty)) {
+ switch (C_CSIZE(tty)) {
case CS5:
channel_setup |= ISICOM_CS5;
break;
@@ -767,7 +771,7 @@ static void isicom_config_port(struct isi_port *port)
flow_ctrl |= ISICOM_INITIATE_XONXOFF;
if (WaitTillCardIsFree(base) == 0) {
- outw(0x8000 | (channel << shift_count) |0x04, base);
+ outw(0x8000 | (channel << shift_count) | 0x04, base);
outw(flow_ctrl << 8 | 0x05, base);
outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
InterruptTheCard(base);
@@ -805,20 +809,17 @@ static int isicom_setup_port(struct isi_port *port)
struct isi_board *card = port->card;
unsigned long flags;
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED)
return 0;
- }
if (!port->xmit_buf) {
- unsigned long page;
-
- if (!(page = get_zeroed_page(GFP_KERNEL)))
+ /* Relies on BKL */
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ if (page == 0)
return -ENOMEM;
-
- if (port->xmit_buf) {
+ if (port->xmit_buf)
free_page(page);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) page;
+ else
+ port->xmit_buf = (unsigned char *) page;
}
spin_lock_irqsave(&card->card_lock, flags);
@@ -949,21 +950,18 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
port->count++;
tty->driver_data = port;
port->tty = tty;
- if ((error = isicom_setup_port(port))!=0)
- return error;
- if ((error = block_til_ready(tty, filp, port))!=0)
- return error;
-
- return 0;
+ error = isicom_setup_port(port);
+ if (error == 0)
+ error = block_til_ready(tty, filp, port);
+ return error;
}
/* close et all */
static inline void isicom_shutdown_board(struct isi_board *bp)
{
- if (bp->status & BOARD_ACTIVE) {
+ if (bp->status & BOARD_ACTIVE)
bp->status &= ~BOARD_ACTIVE;
- }
}
/* card->lock HAS to be held */
@@ -1012,6 +1010,22 @@ static void isicom_shutdown_port(struct isi_port *port)
}
}
+static void isicom_flush_buffer(struct tty_struct *tty)
+{
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
+ return;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&card->card_lock, flags);
+
+ tty_wakeup(tty);
+}
+
static void isicom_close(struct tty_struct *tty, struct file *filp)
{
struct isi_port *port = tty->driver_data;
@@ -1065,8 +1079,7 @@ static void isicom_close(struct tty_struct *tty, struct file *filp)
isicom_shutdown_port(port);
spin_unlock_irqrestore(&card->card_lock, flags);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ isicom_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
@@ -1104,7 +1117,7 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
spin_lock_irqsave(&card->card_lock, flags);
- while(1) {
+ while (1) {
cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
- 1, SERIAL_XMIT_SIZE - port->xmit_head));
if (cnt <= 0)
@@ -1125,28 +1138,29 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
}
/* put_char et all */
-static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
+static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
{
struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card;
unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
- return;
+ return 0;
if (!port->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&card->card_lock, flags);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
spin_unlock_irqrestore(&card->card_lock, flags);
- return;
+ return 0;
}
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt++;
spin_unlock_irqrestore(&card->card_lock, flags);
+ return 1;
}
/* flush_chars et all */
@@ -1258,6 +1272,8 @@ static int isicom_set_serial_info(struct isi_port *port,
if (copy_from_user(&newinfo, info, sizeof(newinfo)))
return -EFAULT;
+ lock_kernel();
+
reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
(newinfo.flags & ASYNC_SPD_MASK));
@@ -1265,12 +1281,13 @@ static int isicom_set_serial_info(struct isi_port *port,
if ((newinfo.close_delay != port->close_delay) ||
(newinfo.closing_wait != port->closing_wait) ||
((newinfo.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK))) {
+ unlock_kernel();
return -EPERM;
- port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
+ }
+ port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(newinfo.flags & ASYNC_USR_MASK));
- }
- else {
+ } else {
port->close_delay = newinfo.close_delay;
port->closing_wait = newinfo.closing_wait;
port->flags = ((port->flags & ~ASYNC_FLAGS) |
@@ -1282,6 +1299,7 @@ static int isicom_set_serial_info(struct isi_port *port,
isicom_config_port(port);
spin_unlock_irqrestore(&port->card->card_lock, flags);
}
+ unlock_kernel();
return 0;
}
@@ -1290,6 +1308,7 @@ static int isicom_get_serial_info(struct isi_port *port,
{
struct serial_struct out_info;
+ lock_kernel();
memset(&out_info, 0, sizeof(out_info));
/* out_info.type = ? */
out_info.line = port - isi_ports;
@@ -1299,6 +1318,7 @@ static int isicom_get_serial_info(struct isi_port *port,
/* out_info.baud_base = ? */
out_info.close_delay = port->close_delay;
out_info.closing_wait = port->closing_wait;
+ unlock_kernel();
if (copy_to_user(info, &out_info, sizeof(out_info)))
return -EFAULT;
return 0;
@@ -1314,7 +1334,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
- switch(cmd) {
+ switch (cmd) {
case TCSBRK:
retval = tty_check_change(tty);
if (retval)
@@ -1331,19 +1351,6 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
tty_wait_until_sent(tty, 0);
isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
return 0;
-
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long __user *)argp);
-
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
-
case TIOCGSERIAL:
return isicom_get_serial_info(port, argp);
@@ -1453,22 +1460,6 @@ static void isicom_hangup(struct tty_struct *tty)
wake_up_interruptible(&port->open_wait);
}
-/* flush_buffer et all */
-static void isicom_flush_buffer(struct tty_struct *tty)
-{
- struct isi_port *port = tty->driver_data;
- struct isi_board *card = port->card;
- unsigned long flags;
-
- if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
- return;
-
- spin_lock_irqsave(&card->card_lock, flags);
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&card->card_lock, flags);
-
- tty_wakeup(tty);
-}
/*
* Driver init and deinit functions
@@ -1592,7 +1583,7 @@ static int __devinit load_firmware(struct pci_dev *pdev,
default:
dev_err(&pdev->dev, "Unknown signature.\n");
goto end;
- }
+ }
retval = request_firmware(&fw, name, &pdev->dev);
if (retval)
@@ -1620,7 +1611,8 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected load header:\n"
KERN_WARNING "Address:0x%x\n"
KERN_WARNING "Count:0x%x\n"
@@ -1637,12 +1629,13 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_err(&pdev->dev, "Card%d got out of sync.Card "
"Status:0x%x\n", index + 1, status);
goto errrelfw;
}
- }
+ }
/* XXX: should we test it by reading it back and comparing with original like
* in load firmware package? */
@@ -1666,7 +1659,8 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
KERN_WARNING "Address:0x%x\n"
KERN_WARNING "Count:0x%x\n"
@@ -1699,7 +1693,8 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_err(&pdev->dev, "Card%d verify got out of sync. "
"Card Status:0x%x\n", index + 1, status);
goto errrelfw;
@@ -1764,7 +1759,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
index + 1);
retval = -EBUSY;
goto errdec;
- }
+ }
retval = request_irq(board->irq, isicom_interrupt,
IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
@@ -1818,7 +1813,7 @@ static int __init isicom_init(void)
int retval, idx, channel;
struct isi_port *port;
- for(idx = 0; idx < BOARD_COUNT; idx++) {
+ for (idx = 0; idx < BOARD_COUNT; idx++) {
port = &isi_ports[idx * 16];
isi_card[idx].ports = port;
spin_lock_init(&isi_card[idx].card_lock);
@@ -1832,7 +1827,7 @@ static int __init isicom_init(void)
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
/* . . . */
- }
+ }
isi_card[idx].base = 0;
isi_card[idx].irq = 0;
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index c645455c3fd..7c8b62f162b 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -1682,16 +1682,6 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
rc = 0;
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) arg);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *) arg)) == 0)
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stli_getserial(portp, argp);
break;
@@ -3267,7 +3257,7 @@ static int stli_initecp(struct stlibrd *brdp)
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL) {
retval = -ENOMEM;
goto err_reg;
@@ -3424,7 +3414,7 @@ static int stli_initonb(struct stlibrd *brdp)
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL) {
retval = -ENOMEM;
goto err_reg;
@@ -3675,7 +3665,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp)
*/
for (i = 0; (i < stli_eisamempsize); i++) {
brdp->memaddr = stli_eisamemprobeaddrs[i];
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL)
continue;
@@ -4433,6 +4423,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
done = 0;
rc = 0;
+ lock_kernel();
+
switch (cmd) {
case COM_GETPORTSTATS:
rc = stli_getportstats(NULL, argp);
@@ -4455,6 +4447,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
done++;
break;
}
+ unlock_kernel();
if (done)
return rc;
@@ -4472,6 +4465,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
if (brdp->state == 0)
return -ENODEV;
+ lock_kernel();
+
switch (cmd) {
case STL_BINTR:
EBRDINTR(brdp);
@@ -4494,6 +4489,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 60b934adea6..7f7e798c138 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -110,6 +110,7 @@ const int max_vals[] = {
const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@ void kd_mksound(unsigned int hz, unsigned int ticks)
} else
kd_nosound(0);
}
+EXPORT_SYMBOL(kd_mksound);
/*
* Setting the keyboard rate.
@@ -1230,7 +1232,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
- (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) {
+ (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
/*
* Don't repeat a key if the input buffers are not empty and the
* characters get aren't echoed locally. This makes key repeat
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index e60a74c66e3..d83db5d880e 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -74,9 +74,8 @@ static const struct file_operations mmtimer_fops = {
* We only have comparison registers RTC1-4 currently available per
* node. RTC0 is used by SAL.
*/
-#define NUM_COMPARATORS 3
/* Check for an RTC interrupt pending */
-static int inline mmtimer_int_pending(int comparator)
+static int mmtimer_int_pending(int comparator)
{
if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) &
SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator)
@@ -84,15 +83,16 @@ static int inline mmtimer_int_pending(int comparator)
else
return 0;
}
+
/* Clear the RTC interrupt pending bit */
-static void inline mmtimer_clr_int_pending(int comparator)
+static void mmtimer_clr_int_pending(int comparator)
{
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator);
}
/* Setup timer on comparator RTC1 */
-static void inline mmtimer_setup_int_0(u64 expires)
+static void mmtimer_setup_int_0(int cpu, u64 expires)
{
u64 val;
@@ -106,7 +106,7 @@ static void inline mmtimer_setup_int_0(u64 expires)
mmtimer_clr_int_pending(0);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC1_INT_CONFIG_PID_SHFT);
/* Set configuration */
@@ -122,7 +122,7 @@ static void inline mmtimer_setup_int_0(u64 expires)
}
/* Setup timer on comparator RTC2 */
-static void inline mmtimer_setup_int_1(u64 expires)
+static void mmtimer_setup_int_1(int cpu, u64 expires)
{
u64 val;
@@ -133,7 +133,7 @@ static void inline mmtimer_setup_int_1(u64 expires)
mmtimer_clr_int_pending(1);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC2_INT_CONFIG_PID_SHFT);
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val);
@@ -144,7 +144,7 @@ static void inline mmtimer_setup_int_1(u64 expires)
}
/* Setup timer on comparator RTC3 */
-static void inline mmtimer_setup_int_2(u64 expires)
+static void mmtimer_setup_int_2(int cpu, u64 expires)
{
u64 val;
@@ -155,7 +155,7 @@ static void inline mmtimer_setup_int_2(u64 expires)
mmtimer_clr_int_pending(2);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC3_INT_CONFIG_PID_SHFT);
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val);
@@ -170,22 +170,22 @@ static void inline mmtimer_setup_int_2(u64 expires)
* in order to insure that the setup succeeds in a deterministic time frame.
* It will check if the interrupt setup succeeded.
*/
-static int inline mmtimer_setup(int comparator, unsigned long expires)
+static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
{
switch (comparator) {
case 0:
- mmtimer_setup_int_0(expires);
+ mmtimer_setup_int_0(cpu, expires);
break;
case 1:
- mmtimer_setup_int_1(expires);
+ mmtimer_setup_int_1(cpu, expires);
break;
case 2:
- mmtimer_setup_int_2(expires);
+ mmtimer_setup_int_2(cpu, expires);
break;
}
/* We might've missed our expiration time */
- if (rtc_time() < expires)
+ if (rtc_time() <= expires)
return 1;
/*
@@ -195,7 +195,7 @@ static int inline mmtimer_setup(int comparator, unsigned long expires)
return mmtimer_int_pending(comparator);
}
-static int inline mmtimer_disable_int(long nasid, int comparator)
+static int mmtimer_disable_int(long nasid, int comparator)
{
switch (comparator) {
case 0:
@@ -216,18 +216,124 @@ static int inline mmtimer_disable_int(long nasid, int comparator)
return 0;
}
-#define TIMER_OFF 0xbadcabLL
+#define COMPARATOR 1 /* The comparator to use */
-/* There is one of these for each comparator */
-typedef struct mmtimer {
- spinlock_t lock ____cacheline_aligned;
+#define TIMER_OFF 0xbadcabLL /* Timer is not setup */
+#define TIMER_SET 0 /* Comparator is set for this timer */
+
+/* There is one of these for each timer */
+struct mmtimer {
+ struct rb_node list;
struct k_itimer *timer;
- int i;
int cpu;
+};
+
+struct mmtimer_node {
+ spinlock_t lock ____cacheline_aligned;
+ struct rb_root timer_head;
+ struct rb_node *next;
struct tasklet_struct tasklet;
-} mmtimer_t;
+};
+static struct mmtimer_node *timers;
+
+
+/*
+ * Add a new mmtimer struct to the node's mmtimer list.
+ * This function assumes the struct mmtimer_node is locked.
+ */
+static void mmtimer_add_list(struct mmtimer *n)
+{
+ int nodeid = n->timer->it.mmtimer.node;
+ unsigned long expires = n->timer->it.mmtimer.expires;
+ struct rb_node **link = &timers[nodeid].timer_head.rb_node;
+ struct rb_node *parent = NULL;
+ struct mmtimer *x;
+
+ /*
+ * Find the right place in the rbtree:
+ */
+ while (*link) {
+ parent = *link;
+ x = rb_entry(parent, struct mmtimer, list);
+
+ if (expires < x->timer->it.mmtimer.expires)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+
+ /*
+ * Insert the timer to the rbtree and check whether it
+ * replaces the first pending timer
+ */
+ rb_link_node(&n->list, parent, link);
+ rb_insert_color(&n->list, &timers[nodeid].timer_head);
+
+ if (!timers[nodeid].next || expires < rb_entry(timers[nodeid].next,
+ struct mmtimer, list)->timer->it.mmtimer.expires)
+ timers[nodeid].next = &n->list;
+}
+
+/*
+ * Set the comparator for the next timer.
+ * This function assumes the struct mmtimer_node is locked.
+ */
+static void mmtimer_set_next_timer(int nodeid)
+{
+ struct mmtimer_node *n = &timers[nodeid];
+ struct mmtimer *x;
+ struct k_itimer *t;
+ int o;
+
+restart:
+ if (n->next == NULL)
+ return;
-static mmtimer_t ** timers;
+ x = rb_entry(n->next, struct mmtimer, list);
+ t = x->timer;
+ if (!t->it.mmtimer.incr) {
+ /* Not an interval timer */
+ if (!mmtimer_setup(x->cpu, COMPARATOR,
+ t->it.mmtimer.expires)) {
+ /* Late setup, fire now */
+ tasklet_schedule(&n->tasklet);
+ }
+ return;
+ }
+
+ /* Interval timer */
+ o = 0;
+ while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) {
+ unsigned long e, e1;
+ struct rb_node *next;
+ t->it.mmtimer.expires += t->it.mmtimer.incr << o;
+ t->it_overrun += 1 << o;
+ o++;
+ if (o > 20) {
+ printk(KERN_ALERT "mmtimer: cannot reschedule timer\n");
+ t->it.mmtimer.clock = TIMER_OFF;
+ n->next = rb_next(&x->list);
+ rb_erase(&x->list, &n->timer_head);
+ kfree(x);
+ goto restart;
+ }
+
+ e = t->it.mmtimer.expires;
+ next = rb_next(&x->list);
+
+ if (next == NULL)
+ continue;
+
+ e1 = rb_entry(next, struct mmtimer, list)->
+ timer->it.mmtimer.expires;
+ if (e > e1) {
+ n->next = next;
+ rb_erase(&x->list, &n->timer_head);
+ mmtimer_add_list(x);
+ goto restart;
+ }
+ }
+}
/**
* mmtimer_ioctl - ioctl interface for /dev/mmtimer
@@ -390,35 +496,6 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
return 0;
}
-/*
- * Schedule the next periodic interrupt. This function will attempt
- * to schedule a periodic interrupt later if necessary. If the scheduling
- * of an interrupt fails then the time to skip is lengthened
- * exponentially in order to ensure that the next interrupt
- * can be properly scheduled..
- */
-static int inline reschedule_periodic_timer(mmtimer_t *x)
-{
- int n;
- struct k_itimer *t = x->timer;
-
- t->it.mmtimer.clock = x->i;
- t->it_overrun--;
-
- n = 0;
- do {
-
- t->it.mmtimer.expires += t->it.mmtimer.incr << n;
- t->it_overrun += 1 << n;
- n++;
- if (n > 20)
- return 1;
-
- } while (!mmtimer_setup(x->i, t->it.mmtimer.expires));
-
- return 0;
-}
-
/**
* mmtimer_interrupt - timer interrupt handler
* @irq: irq received
@@ -435,71 +512,75 @@ static int inline reschedule_periodic_timer(mmtimer_t *x)
static irqreturn_t
mmtimer_interrupt(int irq, void *dev_id)
{
- int i;
unsigned long expires = 0;
int result = IRQ_NONE;
unsigned indx = cpu_to_node(smp_processor_id());
+ struct mmtimer *base;
- /*
- * Do this once for each comparison register
- */
- for (i = 0; i < NUM_COMPARATORS; i++) {
- mmtimer_t *base = timers[indx] + i;
- /* Make sure this doesn't get reused before tasklet_sched */
- spin_lock(&base->lock);
- if (base->cpu == smp_processor_id()) {
- if (base->timer)
- expires = base->timer->it.mmtimer.expires;
- /* expires test won't work with shared irqs */
- if ((mmtimer_int_pending(i) > 0) ||
- (expires && (expires < rtc_time()))) {
- mmtimer_clr_int_pending(i);
- tasklet_schedule(&base->tasklet);
- result = IRQ_HANDLED;
- }
+ spin_lock(&timers[indx].lock);
+ base = rb_entry(timers[indx].next, struct mmtimer, list);
+ if (base == NULL) {
+ spin_unlock(&timers[indx].lock);
+ return result;
+ }
+
+ if (base->cpu == smp_processor_id()) {
+ if (base->timer)
+ expires = base->timer->it.mmtimer.expires;
+ /* expires test won't work with shared irqs */
+ if ((mmtimer_int_pending(COMPARATOR) > 0) ||
+ (expires && (expires <= rtc_time()))) {
+ mmtimer_clr_int_pending(COMPARATOR);
+ tasklet_schedule(&timers[indx].tasklet);
+ result = IRQ_HANDLED;
}
- spin_unlock(&base->lock);
- expires = 0;
}
+ spin_unlock(&timers[indx].lock);
return result;
}
-void mmtimer_tasklet(unsigned long data) {
- mmtimer_t *x = (mmtimer_t *)data;
- struct k_itimer *t = x->timer;
+static void mmtimer_tasklet(unsigned long data)
+{
+ int nodeid = data;
+ struct mmtimer_node *mn = &timers[nodeid];
+ struct mmtimer *x = rb_entry(mn->next, struct mmtimer, list);
+ struct k_itimer *t;
unsigned long flags;
- if (t == NULL)
- return;
-
/* Send signal and deal with periodic signals */
- spin_lock_irqsave(&t->it_lock, flags);
- spin_lock(&x->lock);
- /* If timer was deleted between interrupt and here, leave */
- if (t != x->timer)
+ spin_lock_irqsave(&mn->lock, flags);
+ if (!mn->next)
goto out;
- t->it_overrun = 0;
- if (posix_timer_event(t, 0) != 0) {
+ x = rb_entry(mn->next, struct mmtimer, list);
+ t = x->timer;
+
+ if (t->it.mmtimer.clock == TIMER_OFF)
+ goto out;
+
+ t->it_overrun = 0;
- // printk(KERN_WARNING "mmtimer: cannot deliver signal.\n");
+ mn->next = rb_next(&x->list);
+ rb_erase(&x->list, &mn->timer_head);
+ if (posix_timer_event(t, 0) != 0)
t->it_overrun++;
- }
+
if(t->it.mmtimer.incr) {
- /* Periodic timer */
- if (reschedule_periodic_timer(x)) {
- printk(KERN_WARNING "mmtimer: unable to reschedule\n");
- x->timer = NULL;
- }
+ t->it.mmtimer.expires += t->it.mmtimer.incr;
+ mmtimer_add_list(x);
} else {
/* Ensure we don't false trigger in mmtimer_interrupt */
+ t->it.mmtimer.clock = TIMER_OFF;
t->it.mmtimer.expires = 0;
+ kfree(x);
}
+ /* Set comparator for next timer, if there is one */
+ mmtimer_set_next_timer(nodeid);
+
t->it_overrun_last = t->it_overrun;
out:
- spin_unlock(&x->lock);
- spin_unlock_irqrestore(&t->it_lock, flags);
+ spin_unlock_irqrestore(&mn->lock, flags);
}
static int sgi_timer_create(struct k_itimer *timer)
@@ -516,19 +597,50 @@ static int sgi_timer_create(struct k_itimer *timer)
*/
static int sgi_timer_del(struct k_itimer *timr)
{
- int i = timr->it.mmtimer.clock;
cnodeid_t nodeid = timr->it.mmtimer.node;
- mmtimer_t *t = timers[nodeid] + i;
unsigned long irqflags;
- if (i != TIMER_OFF) {
- spin_lock_irqsave(&t->lock, irqflags);
- mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
- t->timer = NULL;
+ spin_lock_irqsave(&timers[nodeid].lock, irqflags);
+ if (timr->it.mmtimer.clock != TIMER_OFF) {
+ unsigned long expires = timr->it.mmtimer.expires;
+ struct rb_node *n = timers[nodeid].timer_head.rb_node;
+ struct mmtimer *uninitialized_var(t);
+ int r = 0;
+
timr->it.mmtimer.clock = TIMER_OFF;
timr->it.mmtimer.expires = 0;
- spin_unlock_irqrestore(&t->lock, irqflags);
+
+ while (n) {
+ t = rb_entry(n, struct mmtimer, list);
+ if (t->timer == timr)
+ break;
+
+ if (expires < t->timer->it.mmtimer.expires)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+
+ if (!n) {
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
+ return 0;
+ }
+
+ if (timers[nodeid].next == n) {
+ timers[nodeid].next = rb_next(n);
+ r = 1;
+ }
+
+ rb_erase(n, &timers[nodeid].timer_head);
+ kfree(t);
+
+ if (r) {
+ mmtimer_disable_int(cnodeid_to_nasid(nodeid),
+ COMPARATOR);
+ mmtimer_set_next_timer(nodeid);
+ }
}
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
return 0;
}
@@ -557,12 +669,11 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
struct itimerspec * new_setting,
struct itimerspec * old_setting)
{
-
- int i;
unsigned long when, period, irqflags;
int err = 0;
cnodeid_t nodeid;
- mmtimer_t *base;
+ struct mmtimer *base;
+ struct rb_node *n;
if (old_setting)
sgi_timer_get(timr, old_setting);
@@ -575,6 +686,10 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
/* Clear timer */
return 0;
+ base = kmalloc(sizeof(struct mmtimer), GFP_KERNEL);
+ if (base == NULL)
+ return -ENOMEM;
+
if (flags & TIMER_ABSTIME) {
struct timespec n;
unsigned long now;
@@ -604,47 +719,38 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
preempt_disable();
nodeid = cpu_to_node(smp_processor_id());
-retry:
- /* Don't use an allocated timer, or a deleted one that's pending */
- for(i = 0; i< NUM_COMPARATORS; i++) {
- base = timers[nodeid] + i;
- if (!base->timer && !base->tasklet.state) {
- break;
- }
- }
-
- if (i == NUM_COMPARATORS) {
- preempt_enable();
- return -EBUSY;
- }
- spin_lock_irqsave(&base->lock, irqflags);
+ /* Lock the node timer structure */
+ spin_lock_irqsave(&timers[nodeid].lock, irqflags);
- if (base->timer || base->tasklet.state != 0) {
- spin_unlock_irqrestore(&base->lock, irqflags);
- goto retry;
- }
base->timer = timr;
base->cpu = smp_processor_id();
- timr->it.mmtimer.clock = i;
+ timr->it.mmtimer.clock = TIMER_SET;
timr->it.mmtimer.node = nodeid;
timr->it.mmtimer.incr = period;
timr->it.mmtimer.expires = when;
- if (period == 0) {
- if (!mmtimer_setup(i, when)) {
- mmtimer_disable_int(-1, i);
- posix_timer_event(timr, 0);
- timr->it.mmtimer.expires = 0;
- }
- } else {
- timr->it.mmtimer.expires -= period;
- if (reschedule_periodic_timer(base))
- err = -EINVAL;
+ n = timers[nodeid].next;
+
+ /* Add the new struct mmtimer to node's timer list */
+ mmtimer_add_list(base);
+
+ if (timers[nodeid].next == n) {
+ /* No need to reprogram comparator for now */
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
+ preempt_enable();
+ return err;
}
- spin_unlock_irqrestore(&base->lock, irqflags);
+ /* We need to reprogram the comparator */
+ if (n)
+ mmtimer_disable_int(cnodeid_to_nasid(nodeid), COMPARATOR);
+
+ mmtimer_set_next_timer(nodeid);
+
+ /* Unlock the node timer structure */
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
preempt_enable();
@@ -669,7 +775,6 @@ static struct k_clock sgi_clock = {
*/
static int __init mmtimer_init(void)
{
- unsigned i;
cnodeid_t node, maxn = -1;
if (!ia64_platform_is("sn2"))
@@ -706,31 +811,18 @@ static int __init mmtimer_init(void)
maxn++;
/* Allocate list of node ptrs to mmtimer_t's */
- timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+ timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL);
if (timers == NULL) {
printk(KERN_ERR "%s: failed to allocate memory for device\n",
MMTIMER_NAME);
goto out3;
}
- /* Allocate mmtimer_t's for each online node */
+ /* Initialize struct mmtimer's for each online node */
for_each_online_node(node) {
- timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
- if (timers[node] == NULL) {
- printk(KERN_ERR "%s: failed to allocate memory for device\n",
- MMTIMER_NAME);
- goto out4;
- }
- for (i=0; i< NUM_COMPARATORS; i++) {
- mmtimer_t * base = timers[node] + i;
-
- spin_lock_init(&base->lock);
- base->timer = NULL;
- base->cpu = 0;
- base->i = i;
- tasklet_init(&base->tasklet, mmtimer_tasklet,
- (unsigned long) (base));
- }
+ spin_lock_init(&timers[node].lock);
+ tasklet_init(&timers[node].tasklet, mmtimer_tasklet,
+ (unsigned long) node);
}
sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
@@ -741,11 +833,8 @@ static int __init mmtimer_init(void)
return 0;
-out4:
- for_each_online_node(node) {
- kfree(timers[node]);
- }
out3:
+ kfree(timers);
misc_deregister(&mmtimer_miscdev);
out2:
free_irq(SGI_MMTIMER_VECTOR, NULL);
@@ -754,4 +843,3 @@ out1:
}
module_init(mmtimer_init);
-
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 64b7b2b1835..d57d3a61919 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -2,7 +2,8 @@
/*
* moxa.c -- MOXA Intellio family multiport serial driver.
*
- * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com).
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
@@ -25,6 +26,7 @@
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/errno.h>
+#include <linux/firmware.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
@@ -41,21 +43,26 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>
-#include <linux/completion.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#define MOXA_VERSION "5.1k"
+#include "moxa.h"
+
+#define MOXA_VERSION "6.0k"
+
+#define MOXA_FW_HDRLEN 32
#define MOXAMAJOR 172
-#define MOXACUMAJOR 173
#define MAX_BOARDS 4 /* Don't change this value */
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
+#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
+ (brd)->boardType == MOXA_BOARD_C320_PCI)
+
/*
* Define the Moxa PCI vendor and device IDs.
*/
@@ -92,24 +99,16 @@ static struct pci_device_id moxa_pcibrds[] = {
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
#endif /* CONFIG_PCI */
-struct moxa_isa_board_conf {
- int boardType;
- int numPorts;
- unsigned long baseAddr;
-};
-
-static struct moxa_isa_board_conf moxa_isa_boards[] =
-{
-/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */
-};
+struct moxa_port;
static struct moxa_board_conf {
int boardType;
int numPorts;
- unsigned long baseAddr;
int busType;
- int loadstat;
+ unsigned int ready;
+
+ struct moxa_port *ports;
void __iomem *basemem;
void __iomem *intNdx;
@@ -131,30 +130,27 @@ struct moxaq_str {
};
struct moxa_port {
+ struct moxa_board_conf *board;
+ struct tty_struct *tty;
+ void __iomem *tableAddr;
+
int type;
- int port;
int close_delay;
- unsigned short closing_wait;
- int count;
- int blocked_open;
- long event; /* long req'd for set_bit --RR */
+ unsigned int count;
int asyncflags;
- unsigned long statusflags;
- struct tty_struct *tty;
int cflag;
+ unsigned long statusflags;
wait_queue_head_t open_wait;
- struct completion close_wait;
-
- struct timer_list emptyTimer;
- char chkPort;
- char lineCtrl;
- void __iomem *tableAddr;
- long curBaud;
- char DCDState;
- char lowChkFlag;
+ u8 DCDState;
+ u8 lineCtrl;
+ u8 lowChkFlag;
+};
- ushort breakCnt;
+struct mon_str {
+ int tick;
+ int rxcnt[MAX_PORTS];
+ int txcnt[MAX_PORTS];
};
/* statusflags */
@@ -168,20 +164,27 @@ struct moxa_port {
#define WAKEUP_CHARS 256
static int ttymajor = MOXAMAJOR;
+static struct mon_str moxaLog;
+static unsigned int moxaFuncTout = HZ / 2;
+static unsigned int moxaLowWaterChk;
+static DEFINE_MUTEX(moxa_openlock);
/* Variables for insmod */
#ifdef MODULE
-static int baseaddr[4];
-static int type[4];
-static int numports[4];
+static unsigned long baseaddr[MAX_BOARDS];
+static unsigned int type[MAX_BOARDS];
+static unsigned int numports[MAX_BOARDS];
#endif
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
#ifdef MODULE
-module_param_array(type, int, NULL, 0);
-module_param_array(baseaddr, int, NULL, 0);
-module_param_array(numports, int, NULL, 0);
+module_param_array(type, uint, NULL, 0);
+MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
+module_param_array(baseaddr, ulong, NULL, 0);
+MODULE_PARM_DESC(baseaddr, "base address");
+module_param_array(numports, uint, NULL, 0);
+MODULE_PARM_DESC(numports, "numports (ignored for C218)");
#endif
module_param(ttymajor, int, 0);
@@ -194,9 +197,6 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int);
static int moxa_write_room(struct tty_struct *);
static void moxa_flush_buffer(struct tty_struct *);
static int moxa_chars_in_buffer(struct tty_struct *);
-static void moxa_flush_chars(struct tty_struct *);
-static void moxa_put_char(struct tty_struct *, unsigned char);
-static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
static void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
@@ -208,44 +208,183 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static void moxa_poll(unsigned long);
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
-static int moxa_block_till_ready(struct tty_struct *, struct file *,
- struct moxa_port *);
static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_check_xmit_empty(unsigned long);
static void moxa_shut_down(struct moxa_port *);
-static void moxa_receive_data(struct moxa_port *);
/*
* moxa board interface functions:
*/
-static void MoxaDriverInit(void);
-static int MoxaDriverIoctl(unsigned int, unsigned long, int);
-static int MoxaDriverPoll(void);
-static int MoxaPortsOfCard(int);
-static int MoxaPortIsValid(int);
-static void MoxaPortEnable(int);
-static void MoxaPortDisable(int);
-static long MoxaPortGetMaxBaud(int);
-static long MoxaPortSetBaud(int, long);
-static int MoxaPortSetTermio(int, struct ktermios *, speed_t);
-static int MoxaPortGetLineOut(int, int *, int *);
-static void MoxaPortLineCtrl(int, int, int);
-static void MoxaPortFlowCtrl(int, int, int, int, int, int);
-static int MoxaPortLineStatus(int);
-static int MoxaPortDCDChange(int);
-static int MoxaPortDCDON(int);
-static void MoxaPortFlushData(int, int);
-static int MoxaPortWriteData(int, unsigned char *, int);
-static int MoxaPortReadData(int, struct tty_struct *tty);
-static int MoxaPortTxQueue(int);
-static int MoxaPortRxQueue(int);
-static int MoxaPortTxFree(int);
-static void MoxaPortTxDisable(int);
-static void MoxaPortTxEnable(int);
-static int MoxaPortResetBrkCnt(int);
-static void MoxaPortSendBreak(int, int);
+static void MoxaPortEnable(struct moxa_port *);
+static void MoxaPortDisable(struct moxa_port *);
+static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
+static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
+static void MoxaPortLineCtrl(struct moxa_port *, int, int);
+static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
+static int MoxaPortLineStatus(struct moxa_port *);
+static void MoxaPortFlushData(struct moxa_port *, int);
+static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortReadData(struct moxa_port *);
+static int MoxaPortTxQueue(struct moxa_port *);
+static int MoxaPortRxQueue(struct moxa_port *);
+static int MoxaPortTxFree(struct moxa_port *);
+static void MoxaPortTxDisable(struct moxa_port *);
+static void MoxaPortTxEnable(struct moxa_port *);
static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
-static void MoxaSetFifo(int port, int enable);
+static void MoxaSetFifo(struct moxa_port *port, int enable);
+
+/*
+ * I/O functions
+ */
+
+static void moxa_wait_finish(void __iomem *ofsAddr)
+{
+ unsigned long end = jiffies + moxaFuncTout;
+
+ while (readw(ofsAddr + FuncCode) != 0)
+ if (time_after(jiffies, end))
+ return;
+ if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit())
+ printk(KERN_WARNING "moxa function expired\n");
+}
+
+static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
+{
+ writew(arg, ofsAddr + FuncArg);
+ writew(cmd, ofsAddr + FuncCode);
+ moxa_wait_finish(ofsAddr);
+}
+
+static void moxa_low_water_check(void __iomem *ofsAddr)
+{
+ u16 rptr, wptr, mask, len;
+
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
+ rptr = readw(ofsAddr + RXrptr);
+ wptr = readw(ofsAddr + RXwptr);
+ mask = readw(ofsAddr + RX_mask);
+ len = (wptr - rptr) & mask;
+ if (len <= Low_water)
+ moxafunc(ofsAddr, FC_SendXon, 0);
+ }
+}
+
+/*
+ * TTY operations
+ */
+
+static int moxa_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moxa_port *ch = tty->driver_data;
+ void __user *argp = (void __user *)arg;
+ int status, ret = 0;
+
+ if (tty->index == MAX_PORTS) {
+ if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
+ cmd != MOXA_GETMSTATUS)
+ return -EINVAL;
+ } else if (!ch)
+ return -ENODEV;
+
+ switch (cmd) {
+ case MOXA_GETDATACOUNT:
+ moxaLog.tick = jiffies;
+ if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
+ ret = -EFAULT;
+ break;
+ case MOXA_FLUSH_QUEUE:
+ MoxaPortFlushData(ch, arg);
+ break;
+ case MOXA_GET_IOQUEUE: {
+ struct moxaq_str __user *argm = argp;
+ struct moxaq_str tmp;
+ struct moxa_port *p;
+ unsigned int i, j;
+
+ mutex_lock(&moxa_openlock);
+ for (i = 0; i < MAX_BOARDS; i++) {
+ p = moxa_boards[i].ports;
+ for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (moxa_boards[i].ready) {
+ tmp.inq = MoxaPortRxQueue(p);
+ tmp.outq = MoxaPortTxQueue(p);
+ }
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
+ return -EFAULT;
+ }
+ }
+ }
+ mutex_unlock(&moxa_openlock);
+ break;
+ } case MOXA_GET_OQUEUE:
+ status = MoxaPortTxQueue(ch);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
+ case MOXA_GET_IQUEUE:
+ status = MoxaPortRxQueue(ch);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
+ case MOXA_GETMSTATUS: {
+ struct mxser_mstatus __user *argm = argp;
+ struct mxser_mstatus tmp;
+ struct moxa_port *p;
+ unsigned int i, j;
+
+ mutex_lock(&moxa_openlock);
+ for (i = 0; i < MAX_BOARDS; i++) {
+ p = moxa_boards[i].ports;
+ for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (!moxa_boards[i].ready)
+ goto copy;
+
+ status = MoxaPortLineStatus(p);
+ if (status & 1)
+ tmp.cts = 1;
+ if (status & 2)
+ tmp.dsr = 1;
+ if (status & 4)
+ tmp.dcd = 1;
+
+ if (!p->tty || !p->tty->termios)
+ tmp.cflag = p->cflag;
+ else
+ tmp.cflag = p->tty->termios->c_cflag;
+copy:
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
+ return -EFAULT;
+ }
+ }
+ }
+ mutex_unlock(&moxa_openlock);
+ break;
+ }
+ case TIOCGSERIAL:
+ mutex_lock(&moxa_openlock);
+ ret = moxa_get_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ case TIOCSSERIAL:
+ mutex_lock(&moxa_openlock);
+ ret = moxa_set_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+ return ret;
+}
+
+static void moxa_break_ctl(struct tty_struct *tty, int state)
+{
+ struct moxa_port *port = tty->driver_data;
+
+ moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
+ Magic_code);
+}
static const struct tty_operations moxa_ops = {
.open = moxa_open,
@@ -254,8 +393,6 @@ static const struct tty_operations moxa_ops = {
.write_room = moxa_write_room,
.flush_buffer = moxa_flush_buffer,
.chars_in_buffer = moxa_chars_in_buffer,
- .flush_chars = moxa_flush_chars,
- .put_char = moxa_put_char,
.ioctl = moxa_ioctl,
.throttle = moxa_throttle,
.unthrottle = moxa_unthrottle,
@@ -263,15 +400,509 @@ static const struct tty_operations moxa_ops = {
.stop = moxa_stop,
.start = moxa_start,
.hangup = moxa_hangup,
+ .break_ctl = moxa_break_ctl,
.tiocmget = moxa_tiocmget,
.tiocmset = moxa_tiocmset,
};
static struct tty_driver *moxaDriver;
-static struct moxa_port moxa_ports[MAX_PORTS];
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
static DEFINE_SPINLOCK(moxa_lock);
+/*
+ * HW init
+ */
+
+static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
+{
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ if (model != 1)
+ goto err;
+ break;
+ case MOXA_BOARD_CP204J:
+ if (model != 3)
+ goto err;
+ break;
+ default:
+ if (model != 2)
+ goto err;
+ break;
+ }
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static int moxa_check_fw(const void *ptr)
+{
+ const __le16 *lptr = ptr;
+
+ if (*lptr != cpu_to_le16(0x7980))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+ u16 tmp;
+
+ writeb(HW_reset, baseAddr + Control_reg); /* reset */
+ msleep(10);
+ memset_io(baseAddr, 0, 4096);
+ memcpy_toio(baseAddr, buf, len); /* download BIOS */
+ writeb(0, baseAddr + Control_reg); /* restart */
+
+ msleep(2000);
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ tmp = readw(baseAddr + C218_key);
+ if (tmp != C218_KeyCode)
+ goto err;
+ break;
+ case MOXA_BOARD_CP204J:
+ tmp = readw(baseAddr + C218_key);
+ if (tmp != CP204J_KeyCode)
+ goto err;
+ break;
+ default:
+ tmp = readw(baseAddr + C320_key);
+ if (tmp != C320_KeyCode)
+ goto err;
+ tmp = readw(baseAddr + C320_status);
+ if (tmp != STS_init) {
+ printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
+ "module not found\n");
+ return -EIO;
+ }
+ break;
+ }
+
+ return 0;
+err:
+ printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
+ return -EIO;
+}
+
+static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+
+ if (len < 7168) {
+ printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
+ return -EINVAL;
+ }
+
+ writew(len - 7168 - 2, baseAddr + C320bapi_len);
+ writeb(1, baseAddr + Control_reg); /* Select Page 1 */
+ memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
+ writeb(2, baseAddr + Control_reg); /* Select Page 2 */
+ memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
+
+ return 0;
+}
+
+static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+ const u16 *uptr = ptr;
+ size_t wlen, len2, j;
+ unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
+ unsigned int i, retry;
+ u16 usum, keycode;
+
+ keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
+ C218_KeyCode;
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_CP204J:
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ key = C218_key;
+ loadbuf = C218_LoadBuf;
+ loadlen = C218DLoad_len;
+ checksum = C218check_sum;
+ checksum_ok = C218chksum_ok;
+ break;
+ default:
+ key = C320_key;
+ keycode = C320_KeyCode;
+ loadbuf = C320_LoadBuf;
+ loadlen = C320DLoad_len;
+ checksum = C320check_sum;
+ checksum_ok = C320chksum_ok;
+ break;
+ }
+
+ usum = 0;
+ wlen = len >> 1;
+ for (i = 0; i < wlen; i++)
+ usum += le16_to_cpu(uptr[i]);
+ retry = 0;
+ do {
+ wlen = len >> 1;
+ j = 0;
+ while (wlen) {
+ len2 = (wlen > 2048) ? 2048 : wlen;
+ wlen -= len2;
+ memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
+ j += len2 << 1;
+
+ writew(len2, baseAddr + loadlen);
+ writew(0, baseAddr + key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + key) == keycode)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + key) != keycode)
+ return -EIO;
+ }
+ writew(0, baseAddr + loadlen);
+ writew(usum, baseAddr + checksum);
+ writew(0, baseAddr + key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + key) == keycode)
+ break;
+ msleep(10);
+ }
+ retry++;
+ } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
+ if (readb(baseAddr + checksum_ok) != 1)
+ return -EIO;
+
+ writew(0, baseAddr + key);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+
+ if (MOXA_IS_320(brd)) {
+ if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
+ writew(0x3800, baseAddr + TMS320_PORT1);
+ writew(0x3900, baseAddr + TMS320_PORT2);
+ writew(28499, baseAddr + TMS320_CLOCK);
+ } else {
+ writew(0x3200, baseAddr + TMS320_PORT1);
+ writew(0x3400, baseAddr + TMS320_PORT2);
+ writew(19999, baseAddr + TMS320_CLOCK);
+ }
+ }
+ writew(1, baseAddr + Disable_IRQ);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 500; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+
+ if (MOXA_IS_320(brd)) {
+ j = readw(baseAddr + Module_cnt);
+ if (j <= 0)
+ return -EIO;
+ brd->numPorts = j * 8;
+ writew(j, baseAddr + Module_no);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+ }
+ brd->intNdx = baseAddr + IRQindex;
+ brd->intPend = baseAddr + IRQpending;
+ brd->intTable = baseAddr + IRQtable;
+
+ return 0;
+}
+
+static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
+ size_t len)
+{
+ void __iomem *ofsAddr, *baseAddr = brd->basemem;
+ struct moxa_port *port;
+ int retval, i;
+
+ if (len % 2) {
+ printk(KERN_ERR "MOXA: bios length is not even\n");
+ return -EINVAL;
+ }
+
+ retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
+ if (retval)
+ return retval;
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ case MOXA_BOARD_CP204J:
+ port = brd->ports;
+ for (i = 0; i < brd->numPorts; i++, port++) {
+ port->board = brd;
+ port->DCDState = 0;
+ port->tableAddr = baseAddr + Extern_table +
+ Extern_size * i;
+ ofsAddr = port->tableAddr;
+ writew(C218rx_mask, ofsAddr + RX_mask);
+ writew(C218tx_mask, ofsAddr + TX_mask);
+ writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
+
+ writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
+
+ }
+ break;
+ default:
+ port = brd->ports;
+ for (i = 0; i < brd->numPorts; i++, port++) {
+ port->board = brd;
+ port->DCDState = 0;
+ port->tableAddr = baseAddr + Extern_table +
+ Extern_size * i;
+ ofsAddr = port->tableAddr;
+ switch (brd->numPorts) {
+ case 8:
+ writew(C320p8rx_mask, ofsAddr + RX_mask);
+ writew(C320p8tx_mask, ofsAddr + TX_mask);
+ writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
+
+ break;
+ case 16:
+ writew(C320p16rx_mask, ofsAddr + RX_mask);
+ writew(C320p16tx_mask, ofsAddr + TX_mask);
+ writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
+ break;
+
+ case 24:
+ writew(C320p24rx_mask, ofsAddr + RX_mask);
+ writew(C320p24tx_mask, ofsAddr + TX_mask);
+ writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ break;
+ case 32:
+ writew(C320p32rx_mask, ofsAddr + RX_mask);
+ writew(C320p32tx_mask, ofsAddr + TX_mask);
+ writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
+ writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
+ writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
+ writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
+{
+ void *ptr = fw->data;
+ char rsn[64];
+ u16 lens[5];
+ size_t len;
+ unsigned int a, lenp, lencnt;
+ int ret = -EINVAL;
+ struct {
+ __le32 magic; /* 0x34303430 */
+ u8 reserved1[2];
+ u8 type; /* UNIX = 3 */
+ u8 model; /* C218T=1, C320T=2, CP204=3 */
+ u8 reserved2[8];
+ __le16 len[5];
+ } *hdr = ptr;
+
+ BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
+
+ if (fw->size < MOXA_FW_HDRLEN) {
+ strcpy(rsn, "too short (even header won't fit)");
+ goto err;
+ }
+ if (hdr->magic != cpu_to_le32(0x30343034)) {
+ sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
+ goto err;
+ }
+ if (hdr->type != 3) {
+ sprintf(rsn, "not for linux, type is %u", hdr->type);
+ goto err;
+ }
+ if (moxa_check_fw_model(brd, hdr->model)) {
+ sprintf(rsn, "not for this card, model is %u", hdr->model);
+ goto err;
+ }
+
+ len = MOXA_FW_HDRLEN;
+ lencnt = hdr->model == 2 ? 5 : 3;
+ for (a = 0; a < ARRAY_SIZE(lens); a++) {
+ lens[a] = le16_to_cpu(hdr->len[a]);
+ if (lens[a] && len + lens[a] <= fw->size &&
+ moxa_check_fw(&fw->data[len]))
+ printk(KERN_WARNING "MOXA firmware: unexpected input "
+ "at offset %u, but going on\n", (u32)len);
+ if (!lens[a] && a < lencnt) {
+ sprintf(rsn, "too few entries in fw file");
+ goto err;
+ }
+ len += lens[a];
+ }
+
+ if (len != fw->size) {
+ sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
+ (u32)len);
+ goto err;
+ }
+
+ ptr += MOXA_FW_HDRLEN;
+ lenp = 0; /* bios */
+
+ strcpy(rsn, "read above");
+
+ ret = moxa_load_bios(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+
+ /* we skip the tty section (lens[1]), since we don't need it */
+ ptr += lens[lenp] + lens[lenp + 1];
+ lenp += 2; /* comm */
+
+ if (hdr->model == 2) {
+ ret = moxa_load_320b(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+ /* skip another tty */
+ ptr += lens[lenp] + lens[lenp + 1];
+ lenp += 2;
+ }
+
+ ret = moxa_load_code(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
+ return ret;
+}
+
+static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
+{
+ const struct firmware *fw;
+ const char *file;
+ struct moxa_port *p;
+ unsigned int i;
+ int ret;
+
+ brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
+ GFP_KERNEL);
+ if (brd->ports == NULL) {
+ printk(KERN_ERR "cannot allocate memory for ports\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
+ p->type = PORT_16550A;
+ p->close_delay = 5 * HZ / 10;
+ p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ init_waitqueue_head(&p->open_wait);
+ }
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ file = "c218tunx.cod";
+ break;
+ case MOXA_BOARD_CP204J:
+ file = "cp204unx.cod";
+ break;
+ default:
+ file = "c320tunx.cod";
+ break;
+ }
+
+ ret = request_firmware(&fw, file, dev);
+ if (ret) {
+ printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ file);
+ goto err_free;
+ }
+
+ ret = moxa_load_fw(brd, fw);
+
+ release_firmware(fw);
+
+ if (ret)
+ goto err_free;
+
+ spin_lock_bh(&moxa_lock);
+ brd->ready = 1;
+ if (!timer_pending(&moxaTimer))
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock_bh(&moxa_lock);
+
+ return 0;
+err_free:
+ kfree(brd->ports);
+err:
+ return ret;
+}
+
+static void moxa_board_deinit(struct moxa_board_conf *brd)
+{
+ unsigned int a, opened;
+
+ mutex_lock(&moxa_openlock);
+ spin_lock_bh(&moxa_lock);
+ brd->ready = 0;
+ spin_unlock_bh(&moxa_lock);
+
+ /* pci hot-un-plug support */
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+ tty_hangup(brd->ports[a].tty);
+ while (1) {
+ opened = 0;
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+ opened++;
+ mutex_unlock(&moxa_openlock);
+ if (!opened)
+ break;
+ msleep(50);
+ mutex_lock(&moxa_openlock);
+ }
+
+ iounmap(brd->basemem);
+ brd->basemem = NULL;
+ kfree(brd->ports);
+}
+
#ifdef CONFIG_PCI
static int __devinit moxa_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -299,10 +930,17 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
}
board = &moxa_boards[i];
- board->basemem = pci_iomap(pdev, 2, 0x4000);
+
+ retval = pci_request_region(pdev, 2, "moxa-base");
+ if (retval) {
+ dev_err(&pdev->dev, "can't request pci region 2\n");
+ goto err;
+ }
+
+ board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
- goto err;
+ goto err_reg;
}
board->boardType = board_type;
@@ -321,9 +959,21 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
}
board->busType = MOXA_BUS_TYPE_PCI;
+ retval = moxa_init_board(board, &pdev->dev);
+ if (retval)
+ goto err_base;
+
pci_set_drvdata(pdev, board);
- return (0);
+ dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
+ moxa_brdname[board_type - 1], board->numPorts);
+
+ return 0;
+err_base:
+ iounmap(board->basemem);
+ board->basemem = NULL;
+err_reg:
+ pci_release_region(pdev, 2);
err:
return retval;
}
@@ -332,8 +982,9 @@ static void __devexit moxa_pci_remove(struct pci_dev *pdev)
{
struct moxa_board_conf *brd = pci_get_drvdata(pdev);
- pci_iounmap(pdev, brd->basemem);
- brd->basemem = NULL;
+ moxa_board_deinit(brd);
+
+ pci_release_region(pdev, 2);
}
static struct pci_driver moxa_pci_driver = {
@@ -346,8 +997,8 @@ static struct pci_driver moxa_pci_driver = {
static int __init moxa_init(void)
{
- int i, numBoards, retval = 0;
- struct moxa_port *ch;
+ unsigned int isabrds = 0;
+ int retval = 0;
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
@@ -368,154 +1019,176 @@ static int __init moxa_init(void)
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
- for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) {
- ch->type = PORT_16550A;
- ch->port = i;
- ch->close_delay = 5 * HZ / 10;
- ch->closing_wait = 30 * HZ;
- ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- init_waitqueue_head(&ch->open_wait);
- init_completion(&ch->close_wait);
-
- setup_timer(&ch->emptyTimer, moxa_check_xmit_empty,
- (unsigned long)ch);
- }
-
- pr_debug("Moxa tty devices major number = %d\n", ttymajor);
-
if (tty_register_driver(moxaDriver)) {
- printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
+ printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
put_tty_driver(moxaDriver);
return -1;
}
- mod_timer(&moxaTimer, jiffies + HZ / 50);
-
- /* Find the boards defined in source code */
- numBoards = 0;
- for (i = 0; i < MAX_BOARDS; i++) {
- if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) ||
- (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) {
- moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType;
- if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
- moxa_boards[numBoards].numPorts = 8;
- else
- moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts;
- moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
- moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr;
- pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1,
- moxa_brdname[moxa_boards[numBoards].boardType-1],
- moxa_boards[numBoards].baseAddr);
- numBoards++;
- }
- }
- /* Find the boards defined form module args. */
+ /* Find the boards defined from module args. */
#ifdef MODULE
+ {
+ struct moxa_board_conf *brd = moxa_boards;
+ unsigned int i;
for (i = 0; i < MAX_BOARDS; i++) {
- if ((type[i] == MOXA_BOARD_C218_ISA) ||
- (type[i] == MOXA_BOARD_C320_ISA)) {
+ if (!baseaddr[i])
+ break;
+ if (type[i] == MOXA_BOARD_C218_ISA ||
+ type[i] == MOXA_BOARD_C320_ISA) {
pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1, moxa_brdname[type[i] - 1],
- (unsigned long)baseaddr[i]);
- if (numBoards >= MAX_BOARDS) {
- printk(KERN_WARNING "More than %d MOXA "
- "Intellio family boards found. Board "
- "is ignored.\n", MAX_BOARDS);
+ isabrds + 1, moxa_brdname[type[i] - 1],
+ baseaddr[i]);
+ brd->boardType = type[i];
+ brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
+ numports[i];
+ brd->busType = MOXA_BUS_TYPE_ISA;
+ brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
+ if (!brd->basemem) {
+ printk(KERN_ERR "MOXA: can't remap %lx\n",
+ baseaddr[i]);
continue;
}
- moxa_boards[numBoards].boardType = type[i];
- if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
- moxa_boards[numBoards].numPorts = 8;
- else
- moxa_boards[numBoards].numPorts = numports[i];
- moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
- moxa_boards[numBoards].baseAddr = baseaddr[i];
- numBoards++;
+ if (moxa_init_board(brd, NULL)) {
+ iounmap(brd->basemem);
+ brd->basemem = NULL;
+ continue;
+ }
+
+ printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+ "ready (%u ports, firmware loaded)\n",
+ baseaddr[i], brd->numPorts);
+
+ brd++;
+ isabrds++;
}
}
+ }
#endif
#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
if (retval) {
- printk(KERN_ERR "Can't register moxa pci driver!\n");
- if (numBoards)
+ printk(KERN_ERR "Can't register MOXA pci driver!\n");
+ if (isabrds)
retval = 0;
}
#endif
- for (i = 0; i < numBoards; i++) {
- moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr,
- 0x4000);
- }
-
return retval;
}
static void __exit moxa_exit(void)
{
- int i;
+ unsigned int i;
- del_timer_sync(&moxaTimer);
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&moxa_pci_driver);
+#endif
+
+ for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
+ if (moxa_boards[i].ready)
+ moxa_board_deinit(&moxa_boards[i]);
- for (i = 0; i < MAX_PORTS; i++)
- del_timer_sync(&moxa_ports[i].emptyTimer);
+ del_timer_sync(&moxaTimer);
if (tty_unregister_driver(moxaDriver))
printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
"serial driver\n");
put_tty_driver(moxaDriver);
-
-#ifdef CONFIG_PCI
- pci_unregister_driver(&moxa_pci_driver);
-#endif
-
- for (i = 0; i < MAX_BOARDS; i++)
- if (moxa_boards[i].basemem)
- iounmap(moxa_boards[i].basemem);
}
module_init(moxa_init);
module_exit(moxa_exit);
+static void moxa_close_port(struct moxa_port *ch)
+{
+ moxa_shut_down(ch);
+ MoxaPortFlushData(ch, 2);
+ ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
+ ch->tty->driver_data = NULL;
+ ch->tty = NULL;
+}
+
+static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
+ struct moxa_port *ch)
+{
+ DEFINE_WAIT(wait);
+ int retval = 0;
+ u8 dcd;
+
+ while (1) {
+ prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp)) {
+#ifdef SERIAL_DO_RESTART
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ spin_lock_bh(&moxa_lock);
+ dcd = ch->DCDState;
+ spin_unlock_bh(&moxa_lock);
+ if (dcd)
+ break;
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ finish_wait(&ch->open_wait, &wait);
+
+ return retval;
+}
+
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
+ struct moxa_board_conf *brd;
struct moxa_port *ch;
int port;
int retval;
port = tty->index;
if (port == MAX_PORTS) {
- return (0);
+ return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
}
- if (!MoxaPortIsValid(port)) {
- tty->driver_data = NULL;
- return (-ENODEV);
+ if (mutex_lock_interruptible(&moxa_openlock))
+ return -ERESTARTSYS;
+ brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
+ if (!brd->ready) {
+ mutex_unlock(&moxa_openlock);
+ return -ENODEV;
}
- ch = &moxa_ports[port];
+ ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
ch->count++;
tty->driver_data = ch;
ch->tty = tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, tty->termios);
- MoxaPortLineCtrl(ch->port, 1, 1);
- MoxaPortEnable(ch->port);
+ MoxaPortLineCtrl(ch, 1, 1);
+ MoxaPortEnable(ch);
+ MoxaSetFifo(ch, ch->type == PORT_16550A);
ch->asyncflags |= ASYNC_INITIALIZED;
}
- retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_unlock(&moxa_openlock);
- moxa_unthrottle(tty);
-
- if (ch->type == PORT_16550A) {
- MoxaSetFifo(ch->port, 1);
- } else {
- MoxaSetFifo(ch->port, 0);
- }
+ retval = 0;
+ if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
+ retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_lock(&moxa_openlock);
+ if (retval) {
+ if (ch->count) /* 0 means already hung up... */
+ if (--ch->count == 0)
+ moxa_close_port(ch);
+ } else
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+ mutex_unlock(&moxa_openlock);
- return (retval);
+ return retval;
}
static void moxa_close(struct tty_struct *tty, struct file *filp)
@@ -524,23 +1197,14 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
int port;
port = tty->index;
- if (port == MAX_PORTS) {
- return;
- }
- if (!MoxaPortIsValid(port)) {
- pr_debug("Invalid portno in moxa_close\n");
- tty->driver_data = NULL;
- return;
- }
- if (tty->driver_data == NULL) {
+ if (port == MAX_PORTS || tty_hung_up_p(filp))
return;
- }
- if (tty_hung_up_p(filp)) {
- return;
- }
- ch = (struct moxa_port *) tty->driver_data;
- if ((tty->count == 1) && (ch->count != 1)) {
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL)
+ goto unlock;
+ if (tty->count == 1 && ch->count != 1) {
printk(KERN_WARNING "moxa_close: bad serial port count; "
"tty->count is 1, ch->count is %d\n", ch->count);
ch->count = 1;
@@ -550,59 +1214,35 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
"device=%s\n", tty->name);
ch->count = 0;
}
- if (ch->count) {
- return;
- }
- ch->asyncflags |= ASYNC_CLOSING;
+ if (ch->count)
+ goto unlock;
ch->cflag = tty->termios->c_cflag;
if (ch->asyncflags & ASYNC_INITIALIZED) {
moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
- del_timer_sync(&moxa_ports[ch->port].emptyTimer);
- }
- moxa_shut_down(ch);
- MoxaPortFlushData(port, 2);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- ch->event = 0;
- ch->tty = NULL;
- if (ch->blocked_open) {
- if (ch->close_delay) {
- msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
- wake_up_interruptible(&ch->open_wait);
}
- ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- complete_all(&ch->close_wait);
+
+ moxa_close_port(ch);
+unlock:
+ mutex_unlock(&moxa_openlock);
}
static int moxa_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
- struct moxa_port *ch;
- int len, port;
- unsigned long flags;
+ struct moxa_port *ch = tty->driver_data;
+ int len;
- ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
- return (0);
- port = ch->port;
+ return 0;
- spin_lock_irqsave(&moxa_lock, flags);
- len = MoxaPortWriteData(port, (unsigned char *) buf, count);
- spin_unlock_irqrestore(&moxa_lock, flags);
+ spin_lock_bh(&moxa_lock);
+ len = MoxaPortWriteData(ch, buf, count);
+ spin_unlock_bh(&moxa_lock);
- /*********************************************
- if ( !(ch->statusflags & LOWWAIT) &&
- ((len != count) || (MoxaPortTxFree(port) <= 100)) )
- ************************************************/
ch->statusflags |= LOWWAIT;
- return (len);
+ return len;
}
static int moxa_write_room(struct tty_struct *tty)
@@ -610,27 +1250,27 @@ static int moxa_write_room(struct tty_struct *tty)
struct moxa_port *ch;
if (tty->stopped)
- return (0);
- ch = (struct moxa_port *) tty->driver_data;
+ return 0;
+ ch = tty->driver_data;
if (ch == NULL)
- return (0);
- return (MoxaPortTxFree(ch->port));
+ return 0;
+ return MoxaPortTxFree(ch);
}
static void moxa_flush_buffer(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
- MoxaPortFlushData(ch->port, 1);
+ MoxaPortFlushData(ch, 1);
tty_wakeup(tty);
}
static int moxa_chars_in_buffer(struct tty_struct *tty)
{
+ struct moxa_port *ch = tty->driver_data;
int chars;
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
/*
* Sigh...I have to check if driver_data is NULL here, because
@@ -639,8 +1279,9 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
* routine. And since the open() failed, we return 0 here. TDJ
*/
if (ch == NULL)
- return (0);
- chars = MoxaPortTxQueue(ch->port);
+ return 0;
+ lock_kernel();
+ chars = MoxaPortTxQueue(ch);
if (chars) {
/*
* Make it possible to wakeup anything waiting for output
@@ -649,73 +1290,54 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
if (!(ch->statusflags & EMPTYWAIT))
moxa_setup_empty_event(tty);
}
- return (chars);
-}
-
-static void moxa_flush_chars(struct tty_struct *tty)
-{
- /*
- * Don't think I need this, because this is called to empty the TX
- * buffer for the 16450, 16550, etc.
- */
-}
-
-static void moxa_put_char(struct tty_struct *tty, unsigned char c)
-{
- struct moxa_port *ch;
- int port;
- unsigned long flags;
-
- ch = (struct moxa_port *) tty->driver_data;
- if (ch == NULL)
- return;
- port = ch->port;
- spin_lock_irqsave(&moxa_lock, flags);
- MoxaPortWriteData(port, &c, 1);
- spin_unlock_irqrestore(&moxa_lock, flags);
- /************************************************
- if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
- *************************************************/
- ch->statusflags |= LOWWAIT;
+ unlock_kernel();
+ return chars;
}
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
- int port;
+ struct moxa_port *ch;
int flag = 0, dtr, rts;
- port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
+ return -EINVAL;
+ }
- MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr, &rts);
if (dtr)
flag |= TIOCM_DTR;
if (rts)
flag |= TIOCM_RTS;
- dtr = MoxaPortLineStatus(ch->port);
+ dtr = MoxaPortLineStatus(ch);
if (dtr & 1)
flag |= TIOCM_CTS;
if (dtr & 2)
flag |= TIOCM_DSR;
if (dtr & 4)
flag |= TIOCM_CD;
+ mutex_unlock(&moxa_openlock);
return flag;
}
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
int port;
int dtr, rts;
port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
+ return -EINVAL;
+ }
- MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr, &rts);
if (set & TIOCM_RTS)
rts = 1;
if (set & TIOCM_DTR)
@@ -724,105 +1346,51 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
rts = 0;
if (clear & TIOCM_DTR)
dtr = 0;
- MoxaPortLineCtrl(ch->port, dtr, rts);
+ MoxaPortLineCtrl(ch, dtr, rts);
+ mutex_unlock(&moxa_openlock);
return 0;
}
-static int moxa_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
- register int port;
- void __user *argp = (void __user *)arg;
- int retval;
-
- port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return (retval);
- moxa_setup_empty_event(tty);
- tty_wait_until_sent(tty, 0);
- if (!arg)
- MoxaPortSendBreak(ch->port, 0);
- return (0);
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return (retval);
- moxa_setup_empty_event(tty);
- tty_wait_until_sent(tty, 0);
- MoxaPortSendBreak(ch->port, arg);
- return (0);
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
- case TIOCSSOFTCAR:
- if(get_user(retval, (unsigned long __user *) argp))
- return -EFAULT;
- arg = retval;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- if (C_CLOCAL(tty))
- ch->asyncflags &= ~ASYNC_CHECK_CD;
- else
- ch->asyncflags |= ASYNC_CHECK_CD;
- return (0);
- case TIOCGSERIAL:
- return moxa_get_serial_info(ch, argp);
-
- case TIOCSSERIAL:
- return moxa_set_serial_info(ch, argp);
- default:
- retval = MoxaDriverIoctl(cmd, arg, port);
- }
- return (retval);
-}
-
static void moxa_throttle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags |= THROTTLE;
}
static void moxa_unthrottle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags &= ~THROTTLE;
}
static void moxa_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
+ struct ktermios *old_termios)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
moxa_set_tty_param(tty, old_termios);
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&ch->open_wait);
}
static void moxa_stop(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
- MoxaPortTxDisable(ch->port);
+ MoxaPortTxDisable(ch);
ch->statusflags |= TXSTOPPED;
}
static void moxa_start(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
@@ -830,91 +1398,143 @@ static void moxa_start(struct tty_struct *tty)
if (!(ch->statusflags & TXSTOPPED))
return;
- MoxaPortTxEnable(ch->port);
+ MoxaPortTxEnable(ch);
ch->statusflags &= ~TXSTOPPED;
}
static void moxa_hangup(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
- moxa_flush_buffer(tty);
- moxa_shut_down(ch);
- ch->event = 0;
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL) {
+ mutex_unlock(&moxa_openlock);
+ return;
+ }
ch->count = 0;
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- ch->tty = NULL;
+ moxa_close_port(ch);
+ mutex_unlock(&moxa_openlock);
+
wake_up_interruptible(&ch->open_wait);
}
-static void moxa_poll(unsigned long ignored)
+static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{
- register int card;
- struct moxa_port *ch;
- struct tty_struct *tp;
- int i, ports;
+ dcd = !!dcd;
- del_timer(&moxaTimer);
+ if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) {
+ if (!dcd)
+ tty_hangup(p->tty);
+ }
+ p->DCDState = dcd;
+}
- if (MoxaDriverPoll() < 0) {
- mod_timer(&moxaTimer, jiffies + HZ / 50);
- return;
+static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
+ u16 __iomem *ip)
+{
+ struct tty_struct *tty = p->tty;
+ void __iomem *ofsAddr;
+ unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
+ u16 intr;
+
+ if (tty) {
+ if ((p->statusflags & EMPTYWAIT) &&
+ MoxaPortTxQueue(p) == 0) {
+ p->statusflags &= ~EMPTYWAIT;
+ tty_wakeup(tty);
+ }
+ if ((p->statusflags & LOWWAIT) && !tty->stopped &&
+ MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
+ p->statusflags &= ~LOWWAIT;
+ tty_wakeup(tty);
+ }
+
+ if (inited && !(p->statusflags & THROTTLE) &&
+ MoxaPortRxQueue(p) > 0) { /* RX */
+ MoxaPortReadData(p);
+ tty_schedule_flip(tty);
+ }
+ } else {
+ p->statusflags &= ~EMPTYWAIT;
+ MoxaPortFlushData(p, 0); /* flush RX */
}
+
+ if (!handle) /* nothing else to do */
+ return 0;
+
+ intr = readw(ip); /* port irq status */
+ if (intr == 0)
+ return 0;
+
+ writew(0, ip); /* ACK port */
+ ofsAddr = p->tableAddr;
+ if (intr & IntrTx) /* disable tx intr */
+ writew(readw(ofsAddr + HostStat) & ~WakeupTx,
+ ofsAddr + HostStat);
+
+ if (!inited)
+ return 0;
+
+ if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ tty_schedule_flip(tty);
+ }
+
+ if (intr & IntrLine)
+ moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
+
+ return 0;
+}
+
+static void moxa_poll(unsigned long ignored)
+{
+ struct moxa_board_conf *brd;
+ u16 __iomem *ip;
+ unsigned int card, port, served = 0;
+
+ spin_lock(&moxa_lock);
for (card = 0; card < MAX_BOARDS; card++) {
- if ((ports = MoxaPortsOfCard(card)) <= 0)
+ brd = &moxa_boards[card];
+ if (!brd->ready)
continue;
- ch = &moxa_ports[card * MAX_PORTS_PER_BOARD];
- for (i = 0; i < ports; i++, ch++) {
- if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
- continue;
- if (!(ch->statusflags & THROTTLE) &&
- (MoxaPortRxQueue(ch->port) > 0))
- moxa_receive_data(ch);
- if ((tp = ch->tty) == 0)
- continue;
- if (ch->statusflags & LOWWAIT) {
- if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
- if (!tp->stopped) {
- ch->statusflags &= ~LOWWAIT;
- tty_wakeup(tp);
- }
- }
- }
- if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {
- tty_insert_flip_char(tp, 0, TTY_BREAK);
- tty_schedule_flip(tp);
- }
- if (MoxaPortDCDChange(ch->port)) {
- if (ch->asyncflags & ASYNC_CHECK_CD) {
- if (MoxaPortDCDON(ch->port))
- wake_up_interruptible(&ch->open_wait);
- else {
- tty_hangup(tp);
- wake_up_interruptible(&ch->open_wait);
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- }
+
+ served++;
+
+ ip = NULL;
+ if (readb(brd->intPend) == 0xff)
+ ip = brd->intTable + readb(brd->intNdx);
+
+ for (port = 0; port < brd->numPorts; port++)
+ moxa_poll_port(&brd->ports[port], !!ip, ip + port);
+
+ if (ip)
+ writeb(0, brd->intPend); /* ACK */
+
+ if (moxaLowWaterChk) {
+ struct moxa_port *p = brd->ports;
+ for (port = 0; port < brd->numPorts; port++, p++)
+ if (p->lowChkFlag) {
+ p->lowChkFlag = 0;
+ moxa_low_water_check(p->tableAddr);
}
- }
}
}
+ moxaLowWaterChk = 0;
- mod_timer(&moxaTimer, jiffies + HZ / 50);
+ if (served)
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock(&moxa_lock);
}
/******************************************************************************/
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
- register struct ktermios *ts;
- struct moxa_port *ch;
+ register struct ktermios *ts = tty->termios;
+ struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;
- ch = (struct moxa_port *) tty->driver_data;
- ts = tty->termios;
- if (ts->c_cflag & CLOCAL)
- ch->asyncflags &= ~ASYNC_CHECK_CD;
- else
- ch->asyncflags |= ASYNC_CHECK_CD;
rts = cts = txflow = rxflow = xany = 0;
if (ts->c_cflag & CRTSCTS)
rts = cts = 1;
@@ -927,776 +1547,60 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term
/* Clear the features we don't support */
ts->c_cflag &= ~CMSPAR;
- MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
- baud = MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
+ MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
+ baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
if (baud == -1)
baud = tty_termios_baud_rate(old_termios);
/* Not put the baud rate into the termios data */
tty_encode_baud_rate(tty, baud, baud);
}
-static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
- struct moxa_port *ch)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int retval;
- int do_clocal = C_CLOCAL(tty);
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) {
- if (ch->asyncflags & ASYNC_CLOSING)
- wait_for_completion_interruptible(&ch->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- return (-EAGAIN);
- else
- return (-ERESTARTSYS);
-#else
- return (-EAGAIN);
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return (0);
- }
- /*
- * Block waiting for the carrier detect and the line to become free
- */
- retval = 0;
- add_wait_queue(&ch->open_wait, &wait);
- pr_debug("block_til_ready before block: ttys%d, count = %d\n",
- ch->port, ch->count);
- spin_lock_irqsave(&moxa_lock, flags);
- if (!tty_hung_up_p(filp))
- ch->count--;
- ch->blocked_open++;
- spin_unlock_irqrestore(&moxa_lock, flags);
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
- MoxaPortDCDON(ch->port)))
- break;
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ch->open_wait, &wait);
-
- spin_lock_irqsave(&moxa_lock, flags);
- if (!tty_hung_up_p(filp))
- ch->count++;
- ch->blocked_open--;
- spin_unlock_irqrestore(&moxa_lock, flags);
- pr_debug("block_til_ready after blocking: ttys%d, count = %d\n",
- ch->port, ch->count);
- if (retval)
- return (retval);
- /* FIXME: review to see if we need to use set_bit on these */
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
static void moxa_setup_empty_event(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&moxa_lock, flags);
+ spin_lock_bh(&moxa_lock);
ch->statusflags |= EMPTYWAIT;
- mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
- spin_unlock_irqrestore(&moxa_lock, flags);
-}
-
-static void moxa_check_xmit_empty(unsigned long data)
-{
- struct moxa_port *ch;
-
- ch = (struct moxa_port *) data;
- if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
- if (MoxaPortTxQueue(ch->port) == 0) {
- ch->statusflags &= ~EMPTYWAIT;
- tty_wakeup(ch->tty);
- return;
- }
- mod_timer(&moxa_ports[ch->port].emptyTimer,
- round_jiffies(jiffies + HZ));
- } else
- ch->statusflags &= ~EMPTYWAIT;
+ spin_unlock_bh(&moxa_lock);
}
static void moxa_shut_down(struct moxa_port *ch)
{
- struct tty_struct *tp;
+ struct tty_struct *tp = ch->tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
- tp = ch->tty;
-
- MoxaPortDisable(ch->port);
+ MoxaPortDisable(ch);
/*
* If we're a modem control device and HUPCL is on, drop RTS & DTR.
*/
- if (tp->termios->c_cflag & HUPCL)
- MoxaPortLineCtrl(ch->port, 0, 0);
+ if (C_HUPCL(tp))
+ MoxaPortLineCtrl(ch, 0, 0);
+ spin_lock_bh(&moxa_lock);
ch->asyncflags &= ~ASYNC_INITIALIZED;
+ spin_unlock_bh(&moxa_lock);
}
-static void moxa_receive_data(struct moxa_port *ch)
-{
- struct tty_struct *tp;
- struct ktermios *ts;
- unsigned long flags;
-
- ts = NULL;
- tp = ch->tty;
- if (tp)
- ts = tp->termios;
- /**************************************************
- if ( !tp || !ts || !(ts->c_cflag & CREAD) ) {
- *****************************************************/
- if (!tp || !ts) {
- MoxaPortFlushData(ch->port, 0);
- return;
- }
- spin_lock_irqsave(&moxa_lock, flags);
- MoxaPortReadData(ch->port, tp);
- spin_unlock_irqrestore(&moxa_lock, flags);
- tty_schedule_flip(tp);
-}
-
-#define Magic_code 0x404
-
-/*
- * System Configuration
- */
-/*
- * for C218 BIOS initialization
- */
-#define C218_ConfBase 0x800
-#define C218_status (C218_ConfBase + 0) /* BIOS running status */
-#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
-#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
-#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
-#define C218check_sum (C218_ConfBase + 8) /* BYTE */
-#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
-#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
-#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
-#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
-#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
-
-#define C218_LoadBuf 0x0F00
-#define C218_KeyCode 0x218
-#define CP204J_KeyCode 0x204
-
-/*
- * for C320 BIOS initialization
- */
-#define C320_ConfBase 0x800
-#define C320_LoadBuf 0x0f00
-#define STS_init 0x05 /* for C320_status */
-
-#define C320_status C320_ConfBase + 0 /* BIOS running status */
-#define C320_diag C320_ConfBase + 2 /* diagnostic status */
-#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
-#define C320DLoad_len C320_ConfBase + 6 /* WORD */
-#define C320check_sum C320_ConfBase + 8 /* WORD */
-#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
-#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
-#define C320UART_no C320_ConfBase + 0x0e /* WORD */
-
-#define C320_KeyCode 0x320
-
-#define FixPage_addr 0x0000 /* starting addr of static page */
-#define DynPage_addr 0x2000 /* starting addr of dynamic page */
-#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
-#define Control_reg 0x1ff0 /* select page and reset control */
-#define HW_reset 0x80
-
-/*
- * Function Codes
- */
-#define FC_CardReset 0x80
-#define FC_ChannelReset 1 /* C320 firmware not supported */
-#define FC_EnableCH 2
-#define FC_DisableCH 3
-#define FC_SetParam 4
-#define FC_SetMode 5
-#define FC_SetRate 6
-#define FC_LineControl 7
-#define FC_LineStatus 8
-#define FC_XmitControl 9
-#define FC_FlushQueue 10
-#define FC_SendBreak 11
-#define FC_StopBreak 12
-#define FC_LoopbackON 13
-#define FC_LoopbackOFF 14
-#define FC_ClrIrqTable 15
-#define FC_SendXon 16
-#define FC_SetTermIrq 17 /* C320 firmware not supported */
-#define FC_SetCntIrq 18 /* C320 firmware not supported */
-#define FC_SetBreakIrq 19
-#define FC_SetLineIrq 20
-#define FC_SetFlowCtl 21
-#define FC_GenIrq 22
-#define FC_InCD180 23
-#define FC_OutCD180 24
-#define FC_InUARTreg 23
-#define FC_OutUARTreg 24
-#define FC_SetXonXoff 25
-#define FC_OutCD180CCR 26
-#define FC_ExtIQueue 27
-#define FC_ExtOQueue 28
-#define FC_ClrLineIrq 29
-#define FC_HWFlowCtl 30
-#define FC_GetClockRate 35
-#define FC_SetBaud 36
-#define FC_SetDataMode 41
-#define FC_GetCCSR 43
-#define FC_GetDataError 45
-#define FC_RxControl 50
-#define FC_ImmSend 51
-#define FC_SetXonState 52
-#define FC_SetXoffState 53
-#define FC_SetRxFIFOTrig 54
-#define FC_SetTxFIFOCnt 55
-#define FC_UnixRate 56
-#define FC_UnixResetTimer 57
-
-#define RxFIFOTrig1 0
-#define RxFIFOTrig4 1
-#define RxFIFOTrig8 2
-#define RxFIFOTrig14 3
-
-/*
- * Dual-Ported RAM
- */
-#define DRAM_global 0
-#define INT_data (DRAM_global + 0)
-#define Config_base (DRAM_global + 0x108)
-
-#define IRQindex (INT_data + 0)
-#define IRQpending (INT_data + 4)
-#define IRQtable (INT_data + 8)
-
-/*
- * Interrupt Status
- */
-#define IntrRx 0x01 /* receiver data O.K. */
-#define IntrTx 0x02 /* transmit buffer empty */
-#define IntrFunc 0x04 /* function complete */
-#define IntrBreak 0x08 /* received break */
-#define IntrLine 0x10 /* line status change
- for transmitter */
-#define IntrIntr 0x20 /* received INTR code */
-#define IntrQuit 0x40 /* received QUIT code */
-#define IntrEOF 0x80 /* received EOF code */
-
-#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
-#define IntrTxTrigger 0x200 /* tx data count below trigger value */
-
-#define Magic_no (Config_base + 0)
-#define Card_model_no (Config_base + 2)
-#define Total_ports (Config_base + 4)
-#define Module_cnt (Config_base + 8)
-#define Module_no (Config_base + 10)
-#define Timer_10ms (Config_base + 14)
-#define Disable_IRQ (Config_base + 20)
-#define TMS320_PORT1 (Config_base + 22)
-#define TMS320_PORT2 (Config_base + 24)
-#define TMS320_CLOCK (Config_base + 26)
-
-/*
- * DATA BUFFER in DRAM
- */
-#define Extern_table 0x400 /* Base address of the external table
- (24 words * 64) total 3K bytes
- (24 words * 128) total 6K bytes */
-#define Extern_size 0x60 /* 96 bytes */
-#define RXrptr 0x00 /* read pointer for RX buffer */
-#define RXwptr 0x02 /* write pointer for RX buffer */
-#define TXrptr 0x04 /* read pointer for TX buffer */
-#define TXwptr 0x06 /* write pointer for TX buffer */
-#define HostStat 0x08 /* IRQ flag and general flag */
-#define FlagStat 0x0A
-#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
- /* x x x x | | | | */
- /* | | | + CTS flow */
- /* | | +--- RTS flow */
- /* | +------ TX Xon/Xoff */
- /* +--------- RX Xon/Xoff */
-#define Break_cnt 0x0E /* received break count */
-#define CD180TXirq 0x10 /* if non-0: enable TX irq */
-#define RX_mask 0x12
-#define TX_mask 0x14
-#define Ofs_rxb 0x16
-#define Ofs_txb 0x18
-#define Page_rxb 0x1A
-#define Page_txb 0x1C
-#define EndPage_rxb 0x1E
-#define EndPage_txb 0x20
-#define Data_error 0x22
-#define RxTrigger 0x28
-#define TxTrigger 0x2a
-
-#define rRXwptr 0x34
-#define Low_water 0x36
-
-#define FuncCode 0x40
-#define FuncArg 0x42
-#define FuncArg1 0x44
-
-#define C218rx_size 0x2000 /* 8K bytes */
-#define C218tx_size 0x8000 /* 32K bytes */
-
-#define C218rx_mask (C218rx_size - 1)
-#define C218tx_mask (C218tx_size - 1)
-
-#define C320p8rx_size 0x2000
-#define C320p8tx_size 0x8000
-#define C320p8rx_mask (C320p8rx_size - 1)
-#define C320p8tx_mask (C320p8tx_size - 1)
-
-#define C320p16rx_size 0x2000
-#define C320p16tx_size 0x4000
-#define C320p16rx_mask (C320p16rx_size - 1)
-#define C320p16tx_mask (C320p16tx_size - 1)
-
-#define C320p24rx_size 0x2000
-#define C320p24tx_size 0x2000
-#define C320p24rx_mask (C320p24rx_size - 1)
-#define C320p24tx_mask (C320p24tx_size - 1)
-
-#define C320p32rx_size 0x1000
-#define C320p32tx_size 0x1000
-#define C320p32rx_mask (C320p32rx_size - 1)
-#define C320p32tx_mask (C320p32tx_size - 1)
-
-#define Page_size 0x2000
-#define Page_mask (Page_size - 1)
-#define C218rx_spage 3
-#define C218tx_spage 4
-#define C218rx_pageno 1
-#define C218tx_pageno 4
-#define C218buf_pageno 5
-
-#define C320p8rx_spage 3
-#define C320p8tx_spage 4
-#define C320p8rx_pgno 1
-#define C320p8tx_pgno 4
-#define C320p8buf_pgno 5
-
-#define C320p16rx_spage 3
-#define C320p16tx_spage 4
-#define C320p16rx_pgno 1
-#define C320p16tx_pgno 2
-#define C320p16buf_pgno 3
-
-#define C320p24rx_spage 3
-#define C320p24tx_spage 4
-#define C320p24rx_pgno 1
-#define C320p24tx_pgno 1
-#define C320p24buf_pgno 2
-
-#define C320p32rx_spage 3
-#define C320p32tx_ofs C320p32rx_size
-#define C320p32tx_spage 3
-#define C320p32buf_pgno 1
-
-/*
- * Host Status
- */
-#define WakeupRx 0x01
-#define WakeupTx 0x02
-#define WakeupBreak 0x08
-#define WakeupLine 0x10
-#define WakeupIntr 0x20
-#define WakeupQuit 0x40
-#define WakeupEOF 0x80 /* used in VTIME control */
-#define WakeupRxTrigger 0x100
-#define WakeupTxTrigger 0x200
-/*
- * Flag status
- */
-#define Rx_over 0x01
-#define Xoff_state 0x02
-#define Tx_flowOff 0x04
-#define Tx_enable 0x08
-#define CTS_state 0x10
-#define DSR_state 0x20
-#define DCD_state 0x80
-/*
- * FlowControl
- */
-#define CTS_FlowCtl 1
-#define RTS_FlowCtl 2
-#define Tx_FlowCtl 4
-#define Rx_FlowCtl 8
-#define IXM_IXANY 0x10
-
-#define LowWater 128
-
-#define DTR_ON 1
-#define RTS_ON 2
-#define CTS_ON 1
-#define DSR_ON 2
-#define DCD_ON 8
-
-/* mode definition */
-#define MX_CS8 0x03
-#define MX_CS7 0x02
-#define MX_CS6 0x01
-#define MX_CS5 0x00
-
-#define MX_STOP1 0x00
-#define MX_STOP15 0x04
-#define MX_STOP2 0x08
-
-#define MX_PARNONE 0x00
-#define MX_PAREVEN 0x40
-#define MX_PARODD 0xC0
-
-/*
- * Query
- */
-
-struct mon_str {
- int tick;
- int rxcnt[MAX_PORTS];
- int txcnt[MAX_PORTS];
-};
-
-#define DCD_changed 0x01
-#define DCD_oldstate 0x80
-
-static unsigned char moxaBuff[10240];
-static int moxaLowWaterChk;
-static int moxaCard;
-static struct mon_str moxaLog;
-static int moxaFuncTout = HZ / 2;
-
-static void moxafunc(void __iomem *, int, ushort);
-static void moxa_wait_finish(void __iomem *);
-static void moxa_low_water_check(void __iomem *);
-static int moxaloadbios(int, unsigned char __user *, int);
-static int moxafindcard(int);
-static int moxaload320b(int, unsigned char __user *, int);
-static int moxaloadcode(int, unsigned char __user *, int);
-static int moxaloadc218(int, void __iomem *, int);
-static int moxaloadc320(int, void __iomem *, int, int *);
-
/*****************************************************************************
* Driver level functions: *
- * 1. MoxaDriverInit(void); *
- * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); *
- * 3. MoxaDriverPoll(void); *
*****************************************************************************/
-void MoxaDriverInit(void)
-{
- struct moxa_port *p;
- unsigned int i;
- moxaFuncTout = HZ / 2; /* 500 mini-seconds */
- moxaCard = 0;
- moxaLog.tick = 0;
- moxaLowWaterChk = 0;
- for (i = 0; i < MAX_PORTS; i++) {
- p = &moxa_ports[i];
- p->chkPort = 0;
- p->lowChkFlag = 0;
- p->lineCtrl = 0;
- moxaLog.rxcnt[i] = 0;
- moxaLog.txcnt[i] = 0;
- }
-}
-
-#define MOXA 0x400
-#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
-#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
-#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */
-#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */
-#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */
-#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */
-#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */
-#define MOXA_GETDATACOUNT (MOXA + 23)
-#define MOXA_GET_IOQUEUE (MOXA + 27)
-#define MOXA_FLUSH_QUEUE (MOXA + 28)
-#define MOXA_GET_CONF (MOXA + 35) /* configuration */
-#define MOXA_GET_MAJOR (MOXA + 63)
-#define MOXA_GET_CUMAJOR (MOXA + 64)
-#define MOXA_GETMSTATUS (MOXA + 65)
-
-struct dl_str {
- char __user *buf;
- int len;
- int cardno;
-};
-
-static struct dl_str dltmp;
-
-void MoxaPortFlushData(int port, int mode)
+static void MoxaPortFlushData(struct moxa_port *port, int mode)
{
void __iomem *ofsAddr;
- if ((mode < 0) || (mode > 2))
+ if (mode < 0 || mode > 2)
return;
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_FlushQueue, mode);
if (mode != 1) {
- moxa_ports[port].lowChkFlag = 0;
+ port->lowChkFlag = 0;
moxa_low_water_check(ofsAddr);
}
}
-int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
-{
- int i;
- int status;
- int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
- void __user *argp = (void __user *)arg;
-
- if (port == MAX_PORTS) {
- if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) &&
- (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) &&
- (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) &&
- (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) &&
- (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS))
- return (-EINVAL);
- }
- switch (cmd) {
- case MOXA_GET_CONF:
- if(copy_to_user(argp, &moxa_boards, MAX_BOARDS *
- sizeof(struct moxa_board_conf)))
- return -EFAULT;
- return (0);
- case MOXA_INIT_DRIVER:
- if ((int) arg == 0x404)
- MoxaDriverInit();
- return (0);
- case MOXA_GETDATACOUNT:
- moxaLog.tick = jiffies;
- if(copy_to_user(argp, &moxaLog, sizeof(struct mon_str)))
- return -EFAULT;
- return (0);
- case MOXA_FLUSH_QUEUE:
- MoxaPortFlushData(port, arg);
- return (0);
- case MOXA_GET_IOQUEUE: {
- struct moxaq_str __user *argm = argp;
- struct moxaq_str tmp;
-
- for (i = 0; i < MAX_PORTS; i++, argm++) {
- memset(&tmp, 0, sizeof(tmp));
- if (moxa_ports[i].chkPort) {
- tmp.inq = MoxaPortRxQueue(i);
- tmp.outq = MoxaPortTxQueue(i);
- }
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- return (0);
- } case MOXA_GET_OQUEUE:
- i = MoxaPortTxQueue(port);
- return put_user(i, (unsigned long __user *)argp);
- case MOXA_GET_IQUEUE:
- i = MoxaPortRxQueue(port);
- return put_user(i, (unsigned long __user *)argp);
- case MOXA_GET_MAJOR:
- if(copy_to_user(argp, &ttymajor, sizeof(int)))
- return -EFAULT;
- return 0;
- case MOXA_GET_CUMAJOR:
- i = 0;
- if(copy_to_user(argp, &i, sizeof(int)))
- return -EFAULT;
- return 0;
- case MOXA_GETMSTATUS: {
- struct mxser_mstatus __user *argm = argp;
- struct mxser_mstatus tmp;
- struct moxa_port *p;
-
- for (i = 0; i < MAX_PORTS; i++, argm++) {
- p = &moxa_ports[i];
- memset(&tmp, 0, sizeof(tmp));
- if (!p->chkPort) {
- goto copy;
- } else {
- status = MoxaPortLineStatus(p->port);
- if (status & 1)
- tmp.cts = 1;
- if (status & 2)
- tmp.dsr = 1;
- if (status & 4)
- tmp.dcd = 1;
- }
-
- if (!p->tty || !p->tty->termios)
- tmp.cflag = p->cflag;
- else
- tmp.cflag = p->tty->termios->c_cflag;
-copy:
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- return 0;
- } default:
- return (-ENOIOCTLCMD);
- case MOXA_LOAD_BIOS:
- case MOXA_FIND_BOARD:
- case MOXA_LOAD_C320B:
- case MOXA_LOAD_CODE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- break;
- }
-
- if(copy_from_user(&dltmp, argp, sizeof(struct dl_str)))
- return -EFAULT;
- if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0)
- return -EINVAL;
-
- switch(cmd)
- {
- case MOXA_LOAD_BIOS:
- i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
- return (i);
- case MOXA_FIND_BOARD:
- return moxafindcard(dltmp.cardno);
- case MOXA_LOAD_C320B:
- moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
- default: /* to keep gcc happy */
- return (0);
- case MOXA_LOAD_CODE:
- i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
- if (i == -1)
- return (-EFAULT);
- return (i);
-
- }
-}
-
-int MoxaDriverPoll(void)
-{
- struct moxa_board_conf *brd;
- register ushort temp;
- register int card;
- void __iomem *ofsAddr;
- void __iomem *ip;
- int port, p, ports;
-
- if (moxaCard == 0)
- return (-1);
- for (card = 0; card < MAX_BOARDS; card++) {
- brd = &moxa_boards[card];
- if (brd->loadstat == 0)
- continue;
- if ((ports = brd->numPorts) == 0)
- continue;
- if (readb(brd->intPend) == 0xff) {
- ip = brd->intTable + readb(brd->intNdx);
- p = card * MAX_PORTS_PER_BOARD;
- ports <<= 1;
- for (port = 0; port < ports; port += 2, p++) {
- if ((temp = readw(ip + port)) != 0) {
- writew(0, ip + port);
- ofsAddr = moxa_ports[p].tableAddr;
- if (temp & IntrTx)
- writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
- if (temp & IntrBreak) {
- moxa_ports[p].breakCnt++;
- }
- if (temp & IntrLine) {
- if (readb(ofsAddr + FlagStat) & DCD_state) {
- if ((moxa_ports[p].DCDState & DCD_oldstate) == 0)
- moxa_ports[p].DCDState = (DCD_oldstate |
- DCD_changed);
- } else {
- if (moxa_ports[p].DCDState & DCD_oldstate)
- moxa_ports[p].DCDState = DCD_changed;
- }
- }
- }
- }
- writeb(0, brd->intPend);
- }
- if (moxaLowWaterChk) {
- p = card * MAX_PORTS_PER_BOARD;
- for (port = 0; port < ports; port++, p++) {
- if (moxa_ports[p].lowChkFlag) {
- moxa_ports[p].lowChkFlag = 0;
- ofsAddr = moxa_ports[p].tableAddr;
- moxa_low_water_check(ofsAddr);
- }
- }
- }
- }
- moxaLowWaterChk = 0;
- return (0);
-}
-
-/*****************************************************************************
- * Card level function: *
- * 1. MoxaPortsOfCard(int cardno); *
- *****************************************************************************/
-int MoxaPortsOfCard(int cardno)
-{
-
- if (moxa_boards[cardno].boardType == 0)
- return (0);
- return (moxa_boards[cardno].numPorts);
-}
-
-/*****************************************************************************
- * Port level functions: *
- * 1. MoxaPortIsValid(int port); *
- * 2. MoxaPortEnable(int port); *
- * 3. MoxaPortDisable(int port); *
- * 4. MoxaPortGetMaxBaud(int port); *
- * 6. MoxaPortSetBaud(int port, long baud); *
- * 8. MoxaPortSetTermio(int port, unsigned char *termio); *
- * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); *
- * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); *
- * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); *
- * 12. MoxaPortLineStatus(int port); *
- * 13. MoxaPortDCDChange(int port); *
- * 14. MoxaPortDCDON(int port); *
- * 15. MoxaPortFlushData(int port, int mode); *
- * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
- * 17. MoxaPortReadData(int port, struct tty_struct *tty); *
- * 20. MoxaPortTxQueue(int port); *
- * 21. MoxaPortTxFree(int port); *
- * 22. MoxaPortRxQueue(int port); *
- * 24. MoxaPortTxDisable(int port); *
- * 25. MoxaPortTxEnable(int port); *
- * 27. MoxaPortResetBrkCnt(int port); *
- * 30. MoxaPortSendBreak(int port, int ticks); *
- *****************************************************************************/
/*
* Moxa Port Number Description:
*
@@ -1733,33 +1637,6 @@ int MoxaPortsOfCard(int cardno)
* -ENOIOCTLCMD
*
*
- * Function 3: Moxa driver polling process routine.
- * Syntax:
- * int MoxaDriverPoll(void);
- *
- * return: 0 ; polling O.K.
- * -1 : no any Moxa card.
- *
- *
- * Function 4: Get the ports of this card.
- * Syntax:
- * int MoxaPortsOfCard(int cardno);
- *
- * int cardno : card number (0 - 3)
- *
- * return: 0 : this card is invalid
- * 8/16/24/32
- *
- *
- * Function 5: Check this port is valid or invalid
- * Syntax:
- * int MoxaPortIsValid(int port);
- * int port : port number (0 - 127, ref port description)
- *
- * return: 0 : this port is invalid
- * 1 : this port is valid
- *
- *
* Function 6: Enable this port to start Tx/Rx data.
* Syntax:
* void MoxaPortEnable(int port);
@@ -1772,18 +1649,9 @@ int MoxaPortsOfCard(int cardno)
* int port : port number (0 - 127)
*
*
- * Function 8: Get the maximun available baud rate of this port.
- * Syntax:
- * long MoxaPortGetMaxBaud(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : this port is invalid
- * 38400/57600/115200 bps
- *
- *
* Function 10: Setting baud rate of this port.
* Syntax:
- * long MoxaPortSetBaud(int port, long baud);
+ * speed_t MoxaPortSetBaud(int port, speed_t baud);
* int port : port number (0 - 127)
* long baud : baud rate (50 - 115200)
*
@@ -1850,25 +1718,6 @@ int MoxaPortsOfCard(int cardno)
* Bit 2 - DCD state (0: off, 1: on)
*
*
- * Function 17: Check the DCD state has changed since the last read
- * of this function.
- * Syntax:
- * int MoxaPortDCDChange(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : no changed
- * 1 : DCD has changed
- *
- *
- * Function 18: Check ths current DCD state is ON or not.
- * Syntax:
- * int MoxaPortDCDON(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : DCD off
- * 1 : DCD on
- *
- *
* Function 19: Flush the Rx/Tx buffer data of this port.
* Syntax:
* void MoxaPortFlushData(int port, int mode);
@@ -1942,40 +1791,20 @@ int MoxaPortsOfCard(int cardno)
* return: 0 - .. : BREAK signal count
*
*
- * Function 34: Send out a BREAK signal.
- * Syntax:
- * void MoxaPortSendBreak(int port, int ms100);
- * int port : port number (0 - 127)
- * int ms100 : break signal time interval.
- * unit: 100 mini-second. if ms100 == 0, it will
- * send out a about 250 ms BREAK signal.
- *
*/
-int MoxaPortIsValid(int port)
-{
-
- if (moxaCard == 0)
- return (0);
- if (moxa_ports[port].chkPort == 0)
- return (0);
- return (1);
-}
-void MoxaPortEnable(int port)
+static void MoxaPortEnable(struct moxa_port *port)
{
void __iomem *ofsAddr;
- int MoxaPortLineStatus(int);
- short lowwater = 512;
+ u16 lowwater = 512;
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
writew(lowwater, ofsAddr + Low_water);
- moxa_ports[port].breakCnt = 0;
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ if (MOXA_IS_320(port->board))
moxafunc(ofsAddr, FC_SetBreakIrq, 0);
- } else {
- writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
- }
+ else
+ writew(readw(ofsAddr + HostStat) | WakeupBreak,
+ ofsAddr + HostStat);
moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
moxafunc(ofsAddr, FC_FlushQueue, 2);
@@ -1984,9 +1813,9 @@ void MoxaPortEnable(int port)
MoxaPortLineStatus(port);
}
-void MoxaPortDisable(int port)
+static void MoxaPortDisable(struct moxa_port *port)
{
- void __iomem *ofsAddr = moxa_ports[port].tableAddr;
+ void __iomem *ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */
moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
@@ -1994,49 +1823,32 @@ void MoxaPortDisable(int port)
moxafunc(ofsAddr, FC_DisableCH, Magic_code);
}
-long MoxaPortGetMaxBaud(int port)
-{
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI))
- return (460800L);
- else
- return (921600L);
-}
-
-
-long MoxaPortSetBaud(int port, long baud)
+static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
{
- void __iomem *ofsAddr;
- long max, clock;
- unsigned int val;
+ void __iomem *ofsAddr = port->tableAddr;
+ unsigned int clock, val;
+ speed_t max;
- if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
- return (0);
- ofsAddr = moxa_ports[port].tableAddr;
+ max = MOXA_IS_320(port->board) ? 460800 : 921600;
+ if (baud < 50)
+ return 0;
if (baud > max)
baud = max;
- if (max == 38400L)
- clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */
- else if (max == 57600L)
- clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */
- else
- clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */
+ clock = 921600;
val = clock / baud;
moxafunc(ofsAddr, FC_SetBaud, val);
baud = clock / val;
- moxa_ports[port].curBaud = baud;
- return (baud);
+ return baud;
}
-int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
+static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
+ speed_t baud)
{
void __iomem *ofsAddr;
tcflag_t cflag;
tcflag_t mode = 0;
- if (moxa_ports[port].chkPort == 0 || termio == 0)
- return (-1);
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
cflag = termio->c_cflag; /* termio->c_cflag */
mode = termio->c_cflag & CSIZE;
@@ -2065,13 +1877,11 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
} else
mode |= MX_PARNONE;
- moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+ moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
+
+ if (MOXA_IS_320(port->board) && baud >= 921600)
+ return -1;
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
- if (baud >= 921600L)
- return (-1);
- }
baud = MoxaPortSetBaud(port, baud);
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
@@ -2081,51 +1891,37 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
moxa_wait_finish(ofsAddr);
}
- return (baud);
+ return baud;
}
-int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
+static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
+ int *rtsState)
{
+ if (dtrState)
+ *dtrState = !!(port->lineCtrl & DTR_ON);
+ if (rtsState)
+ *rtsState = !!(port->lineCtrl & RTS_ON);
- if (!MoxaPortIsValid(port))
- return (-1);
- if (dtrState) {
- if (moxa_ports[port].lineCtrl & DTR_ON)
- *dtrState = 1;
- else
- *dtrState = 0;
- }
- if (rtsState) {
- if (moxa_ports[port].lineCtrl & RTS_ON)
- *rtsState = 1;
- else
- *rtsState = 0;
- }
- return (0);
+ return 0;
}
-void MoxaPortLineCtrl(int port, int dtr, int rts)
+static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
{
- void __iomem *ofsAddr;
- int mode;
+ u8 mode = 0;
- ofsAddr = moxa_ports[port].tableAddr;
- mode = 0;
if (dtr)
mode |= DTR_ON;
if (rts)
mode |= RTS_ON;
- moxa_ports[port].lineCtrl = mode;
- moxafunc(ofsAddr, FC_LineControl, mode);
+ port->lineCtrl = mode;
+ moxafunc(port->tableAddr, FC_LineControl, mode);
}
-void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany)
+static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
+ int txflow, int rxflow, int txany)
{
- void __iomem *ofsAddr;
- int mode;
+ int mode = 0;
- ofsAddr = moxa_ports[port].tableAddr;
- mode = 0;
if (rts)
mode |= RTS_FlowCtl;
if (cts)
@@ -2136,81 +1932,50 @@ void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int tx
mode |= Rx_FlowCtl;
if (txany)
mode |= IXM_IXANY;
- moxafunc(ofsAddr, FC_SetFlowCtl, mode);
+ moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
}
-int MoxaPortLineStatus(int port)
+static int MoxaPortLineStatus(struct moxa_port *port)
{
void __iomem *ofsAddr;
int val;
- ofsAddr = moxa_ports[port].tableAddr;
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ ofsAddr = port->tableAddr;
+ if (MOXA_IS_320(port->board)) {
moxafunc(ofsAddr, FC_LineStatus, 0);
val = readw(ofsAddr + FuncArg);
} else {
val = readw(ofsAddr + FlagStat) >> 4;
}
val &= 0x0B;
- if (val & 8) {
+ if (val & 8)
val |= 4;
- if ((moxa_ports[port].DCDState & DCD_oldstate) == 0)
- moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed);
- } else {
- if (moxa_ports[port].DCDState & DCD_oldstate)
- moxa_ports[port].DCDState = DCD_changed;
- }
+ spin_lock_bh(&moxa_lock);
+ moxa_new_dcdstate(port, val & 8);
+ spin_unlock_bh(&moxa_lock);
val &= 7;
- return (val);
-}
-
-int MoxaPortDCDChange(int port)
-{
- int n;
-
- if (moxa_ports[port].chkPort == 0)
- return (0);
- n = moxa_ports[port].DCDState;
- moxa_ports[port].DCDState &= ~DCD_changed;
- n &= DCD_changed;
- return (n);
-}
-
-int MoxaPortDCDON(int port)
-{
- int n;
-
- if (moxa_ports[port].chkPort == 0)
- return (0);
- if (moxa_ports[port].DCDState & DCD_oldstate)
- n = 1;
- else
- n = 0;
- return (n);
+ return val;
}
-int MoxaPortWriteData(int port, unsigned char * buffer, int len)
+static int MoxaPortWriteData(struct moxa_port *port,
+ const unsigned char *buffer, int len)
{
- int c, total, i;
- ushort tail;
- int cnt;
- ushort head, tx_mask, spage, epage;
- ushort pageno, pageofs, bufhead;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ unsigned int c, total;
+ u16 head, tail, tx_mask, spage, epage;
+ u16 pageno, pageofs, bufhead;
- ofsAddr = moxa_ports[port].tableAddr;
- baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
+ ofsAddr = port->tableAddr;
+ baseAddr = port->board->basemem;
tx_mask = readw(ofsAddr + TX_mask);
spage = readw(ofsAddr + Page_txb);
epage = readw(ofsAddr + EndPage_txb);
tail = readw(ofsAddr + TXwptr);
head = readw(ofsAddr + TXrptr);
- c = (head > tail) ? (head - tail - 1)
- : (head - tail + tx_mask);
+ c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
if (c > len)
c = len;
- moxaLog.txcnt[port] += c;
+ moxaLog.txcnt[port->tty->index] += c;
total = c;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_txb);
@@ -2222,249 +1987,179 @@ int MoxaPortWriteData(int port, unsigned char * buffer, int len)
len = tx_mask + 1 - tail;
len = (c > len) ? len : c;
ofs = baseAddr + DynPage_addr + bufhead + tail;
- for (i = 0; i < len; i++)
- writeb(*buffer++, ofs + i);
+ memcpy_toio(ofs, buffer, len);
+ buffer += len;
tail = (tail + len) & tx_mask;
c -= len;
}
- writew(tail, ofsAddr + TXwptr);
} else {
- len = c;
pageno = spage + (tail >> 13);
pageofs = tail & Page_mask;
- do {
- cnt = Page_size - pageofs;
- if (cnt > c)
- cnt = c;
- c -= cnt;
+ while (c > 0) {
+ len = Page_size - pageofs;
+ if (len > c)
+ len = c;
writeb(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
- for (i = 0; i < cnt; i++)
- writeb(*buffer++, ofs + i);
- if (c == 0) {
- writew((tail + len) & tx_mask, ofsAddr + TXwptr);
- break;
- }
+ memcpy_toio(ofs, buffer, len);
+ buffer += len;
if (++pageno == epage)
pageno = spage;
pageofs = 0;
- } while (1);
+ c -= len;
+ }
+ tail = (tail + total) & tx_mask;
}
+ writew(tail, ofsAddr + TXwptr);
writeb(1, ofsAddr + CD180TXirq); /* start to send */
- return (total);
+ return total;
}
-int MoxaPortReadData(int port, struct tty_struct *tty)
+static int MoxaPortReadData(struct moxa_port *port)
{
- register ushort head, pageofs;
- int i, count, cnt, len, total, remain;
- ushort tail, rx_mask, spage, epage;
- ushort pageno, bufhead;
+ struct tty_struct *tty = port->tty;
+ unsigned char *dst;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ unsigned int count, len, total;
+ u16 tail, rx_mask, spage, epage;
+ u16 pageno, pageofs, bufhead, head;
- ofsAddr = moxa_ports[port].tableAddr;
- baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
+ ofsAddr = port->tableAddr;
+ baseAddr = port->board->basemem;
head = readw(ofsAddr + RXrptr);
tail = readw(ofsAddr + RXwptr);
rx_mask = readw(ofsAddr + RX_mask);
spage = readw(ofsAddr + Page_rxb);
epage = readw(ofsAddr + EndPage_rxb);
- count = (tail >= head) ? (tail - head)
- : (tail - head + rx_mask + 1);
+ count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
if (count == 0)
return 0;
total = count;
- remain = count - total;
- moxaLog.rxcnt[port] += total;
- count = total;
+ moxaLog.rxcnt[tty->index] += total;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_rxb);
writew(spage, baseAddr + Control_reg);
while (count > 0) {
- if (tail >= head)
- len = tail - head;
- else
- len = rx_mask + 1 - head;
- len = (count > len) ? len : count;
ofs = baseAddr + DynPage_addr + bufhead + head;
- for (i = 0; i < len; i++)
- tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
+ len = (tail >= head) ? (tail - head) :
+ (rx_mask + 1 - head);
+ len = tty_prepare_flip_string(tty, &dst,
+ min(len, count));
+ memcpy_fromio(dst, ofs, len);
head = (head + len) & rx_mask;
count -= len;
}
- writew(head, ofsAddr + RXrptr);
} else {
- len = count;
pageno = spage + (head >> 13);
pageofs = head & Page_mask;
- do {
- cnt = Page_size - pageofs;
- if (cnt > count)
- cnt = count;
- count -= cnt;
+ while (count > 0) {
writew(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
- for (i = 0; i < cnt; i++)
- tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
- if (count == 0) {
- writew((head + len) & rx_mask, ofsAddr + RXrptr);
- break;
- }
- if (++pageno == epage)
+ len = tty_prepare_flip_string(tty, &dst,
+ min(Page_size - pageofs, count));
+ memcpy_fromio(dst, ofs, len);
+
+ count -= len;
+ pageofs = (pageofs + len) & Page_mask;
+ if (pageofs == 0 && ++pageno == epage)
pageno = spage;
- pageofs = 0;
- } while (1);
+ }
+ head = (head + total) & rx_mask;
}
- if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
+ writew(head, ofsAddr + RXrptr);
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
moxaLowWaterChk = 1;
- moxa_ports[port].lowChkFlag = 1;
+ port->lowChkFlag = 1;
}
- return (total);
+ return total;
}
-int MoxaPortTxQueue(int port)
+static int MoxaPortTxQueue(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
- len = (wptr - rptr) & mask;
- return (len);
+ return (wptr - rptr) & mask;
}
-int MoxaPortTxFree(int port)
+static int MoxaPortTxFree(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
- len = mask - ((wptr - rptr) & mask);
- return (len);
+ return mask - ((wptr - rptr) & mask);
}
-int MoxaPortRxQueue(int port)
+static int MoxaPortRxQueue(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + RXrptr);
wptr = readw(ofsAddr + RXwptr);
mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- return (len);
+ return (wptr - rptr) & mask;
}
-
-void MoxaPortTxDisable(int port)
+static void MoxaPortTxDisable(struct moxa_port *port)
{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
+ moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
}
-void MoxaPortTxEnable(int port)
+static void MoxaPortTxEnable(struct moxa_port *port)
{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- moxafunc(ofsAddr, FC_SetXonState, Magic_code);
-}
-
-
-int MoxaPortResetBrkCnt(int port)
-{
- ushort cnt;
- cnt = moxa_ports[port].breakCnt;
- moxa_ports[port].breakCnt = 0;
- return (cnt);
-}
-
-
-void MoxaPortSendBreak(int port, int ms100)
-{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- if (ms100) {
- moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- msleep(ms100 * 10);
- } else {
- moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- msleep(250);
- }
- moxafunc(ofsAddr, FC_StopBreak, Magic_code);
+ moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
}
static int moxa_get_serial_info(struct moxa_port *info,
- struct serial_struct __user *retinfo)
+ struct serial_struct __user *retinfo)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->port;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.flags = info->asyncflags;
- tmp.baud_base = 921600;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = 0;
- tmp.hub6 = 0;
- if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return (0);
+ struct serial_struct tmp = {
+ .type = info->type,
+ .line = info->tty->index,
+ .flags = info->asyncflags,
+ .baud_base = 921600,
+ .close_delay = info->close_delay
+ };
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
static int moxa_set_serial_info(struct moxa_port *info,
- struct serial_struct __user *new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
- if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- if ((new_serial.irq != 0) ||
- (new_serial.port != 0) ||
-// (new_serial.type != info->type) ||
- (new_serial.custom_divisor != 0) ||
- (new_serial.baud_base != 921600))
- return (-EPERM);
+ if (new_serial.irq != 0 || new_serial.port != 0 ||
+ new_serial.custom_divisor != 0 ||
+ new_serial.baud_base != 921600)
+ return -EPERM;
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->asyncflags & ~ASYNC_USR_MASK)))
- return (-EPERM);
- } else {
+ return -EPERM;
+ } else
info->close_delay = new_serial.close_delay * HZ / 100;
- info->closing_wait = new_serial.closing_wait * HZ / 100;
- }
new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
- if (new_serial.type == PORT_16550A) {
- MoxaSetFifo(info->port, 1);
- } else {
- MoxaSetFifo(info->port, 0);
- }
+ MoxaSetFifo(info, new_serial.type == PORT_16550A);
info->type = new_serial.type;
- return (0);
+ return 0;
}
@@ -2472,374 +2167,10 @@ static int moxa_set_serial_info(struct moxa_port *info,
/*****************************************************************************
* Static local functions: *
*****************************************************************************/
-static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
-{
-
- writew(arg, ofsAddr + FuncArg);
- writew(cmd, ofsAddr + FuncCode);
- moxa_wait_finish(ofsAddr);
-}
-
-static void moxa_wait_finish(void __iomem *ofsAddr)
-{
- unsigned long i, j;
-
- i = jiffies;
- while (readw(ofsAddr + FuncCode) != 0) {
- j = jiffies;
- if ((j - i) > moxaFuncTout) {
- return;
- }
- }
-}
-
-static void moxa_low_water_check(void __iomem *ofsAddr)
-{
- int len;
- ushort rptr, wptr, mask;
-
- if (readb(ofsAddr + FlagStat) & Xoff_state) {
- rptr = readw(ofsAddr + RXrptr);
- wptr = readw(ofsAddr + RXwptr);
- mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- if (len <= Low_water)
- moxafunc(ofsAddr, FC_SendXon, 0);
- }
-}
-
-static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr;
- int i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- writeb(HW_reset, baseAddr + Control_reg); /* reset */
- msleep(10);
- for (i = 0; i < 4096; i++)
- writeb(0, baseAddr + i); /* clear fix page */
- for (i = 0; i < len; i++)
- writeb(moxaBuff[i], baseAddr + i); /* download BIOS */
- writeb(0, baseAddr + Control_reg); /* restart */
- return (0);
-}
-
-static int moxafindcard(int cardno)
-{
- void __iomem *baseAddr;
- ushort tmp;
-
- baseAddr = moxa_boards[cardno].basemem;
- switch (moxa_boards[cardno].boardType) {
- case MOXA_BOARD_C218_ISA:
- case MOXA_BOARD_C218_PCI:
- if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) {
- return (-1);
- }
- break;
- case MOXA_BOARD_CP204J:
- if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) {
- return (-1);
- }
- break;
- default:
- if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) {
- return (-1);
- }
- if ((tmp = readw(baseAddr + C320_status)) != STS_init) {
- return (-2);
- }
- }
- return (0);
-}
-
-static int moxaload320b(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr;
- int i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- writew(len - 7168 - 2, baseAddr + C320bapi_len);
- writeb(1, baseAddr + Control_reg); /* Select Page 1 */
- for (i = 0; i < 7168; i++)
- writeb(moxaBuff[i], baseAddr + DynPage_addr + i);
- writeb(2, baseAddr + Control_reg); /* Select Page 2 */
- for (i = 0; i < (len - 7168); i++)
- writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i);
- return (0);
-}
-
-static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr, *ofsAddr;
- int retval, port, i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- switch (moxa_boards[cardno].boardType) {
- case MOXA_BOARD_C218_ISA:
- case MOXA_BOARD_C218_PCI:
- case MOXA_BOARD_CP204J:
- retval = moxaloadc218(cardno, baseAddr, len);
- if (retval)
- return (retval);
- port = cardno * MAX_PORTS_PER_BOARD;
- for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
- struct moxa_port *p = &moxa_ports[port];
-
- p->chkPort = 1;
- p->curBaud = 9600L;
- p->DCDState = 0;
- p->tableAddr = baseAddr + Extern_table + Extern_size * i;
- ofsAddr = p->tableAddr;
- writew(C218rx_mask, ofsAddr + RX_mask);
- writew(C218tx_mask, ofsAddr + TX_mask);
- writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
-
- writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
-
- }
- break;
- default:
- retval = moxaloadc320(cardno, baseAddr, len,
- &moxa_boards[cardno].numPorts);
- if (retval)
- return (retval);
- port = cardno * MAX_PORTS_PER_BOARD;
- for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
- struct moxa_port *p = &moxa_ports[port];
-
- p->chkPort = 1;
- p->curBaud = 9600L;
- p->DCDState = 0;
- p->tableAddr = baseAddr + Extern_table + Extern_size * i;
- ofsAddr = p->tableAddr;
- if (moxa_boards[cardno].numPorts == 8) {
- writew(C320p8rx_mask, ofsAddr + RX_mask);
- writew(C320p8tx_mask, ofsAddr + TX_mask);
- writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
-
- } else if (moxa_boards[cardno].numPorts == 16) {
- writew(C320p16rx_mask, ofsAddr + RX_mask);
- writew(C320p16tx_mask, ofsAddr + TX_mask);
- writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
-
- } else if (moxa_boards[cardno].numPorts == 24) {
- writew(C320p24rx_mask, ofsAddr + RX_mask);
- writew(C320p24tx_mask, ofsAddr + TX_mask);
- writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- } else if (moxa_boards[cardno].numPorts == 32) {
- writew(C320p32rx_mask, ofsAddr + RX_mask);
- writew(C320p32tx_mask, ofsAddr + TX_mask);
- writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
- writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
- writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
- writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- }
- }
- break;
- }
- moxa_boards[cardno].loadstat = 1;
- return (0);
-}
-
-static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
-{
- char retry;
- int i, j, len1, len2;
- ushort usum, *ptr, keycode;
-
- if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J)
- keycode = CP204J_KeyCode;
- else
- keycode = C218_KeyCode;
- usum = 0;
- len1 = len >> 1;
- ptr = (ushort *) moxaBuff;
- for (i = 0; i < len1; i++)
- usum += le16_to_cpu(*(ptr + i));
- retry = 0;
- do {
- len1 = len >> 1;
- j = 0;
- while (len1) {
- len2 = (len1 > 2048) ? 2048 : len1;
- len1 -= len2;
- for (i = 0; i < len2 << 1; i++)
- writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i);
- j += i;
-
- writew(len2, baseAddr + C218DLoad_len);
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + C218_key) == keycode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + C218_key) != keycode) {
- return (-1);
- }
- }
- writew(0, baseAddr + C218DLoad_len);
- writew(usum, baseAddr + C218check_sum);
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + C218_key) == keycode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + C218chksum_ok) != 1) {
- return (-1);
- }
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code) {
- return (-1);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code) {
- return (-1);
- }
- moxaCard = 1;
- moxa_boards[cardno].intNdx = baseAddr + IRQindex;
- moxa_boards[cardno].intPend = baseAddr + IRQpending;
- moxa_boards[cardno].intTable = baseAddr + IRQtable;
- return (0);
-}
-
-static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPorts)
-{
- ushort usum;
- int i, j, wlen, len2, retry;
- ushort *uptr;
-
- usum = 0;
- wlen = len >> 1;
- uptr = (ushort *) moxaBuff;
- for (i = 0; i < wlen; i++)
- usum += le16_to_cpu(uptr[i]);
- retry = 0;
- j = 0;
- do {
- while (wlen) {
- if (wlen > 2048)
- len2 = 2048;
- else
- len2 = wlen;
- wlen -= len2;
- len2 <<= 1;
- for (i = 0; i < len2; i++)
- writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i);
- len2 >>= 1;
- j += i;
- writew(len2, baseAddr + C320DLoad_len);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 10; i++) {
- if (readw(baseAddr + C320_key) == C320_KeyCode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + C320_key) != C320_KeyCode)
- return (-1);
- }
- writew(0, baseAddr + C320DLoad_len);
- writew(usum, baseAddr + C320check_sum);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 10; i++) {
- if (readw(baseAddr + C320_key) == C320_KeyCode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + C320chksum_ok) != 1)
- return (-1);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-100);
-
- if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
- writew(0x3800, baseAddr + TMS320_PORT1);
- writew(0x3900, baseAddr + TMS320_PORT2);
- writew(28499, baseAddr + TMS320_CLOCK);
- } else {
- writew(0x3200, baseAddr + TMS320_PORT1);
- writew(0x3400, baseAddr + TMS320_PORT2);
- writew(19999, baseAddr + TMS320_CLOCK);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 500; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-102);
-
- j = readw(baseAddr + Module_cnt);
- if (j <= 0)
- return (-101);
- *numPorts = j * 8;
- writew(j, baseAddr + Module_no);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-102);
- moxaCard = 1;
- moxa_boards[cardno].intNdx = baseAddr + IRQindex;
- moxa_boards[cardno].intPend = baseAddr + IRQpending;
- moxa_boards[cardno].intTable = baseAddr + IRQtable;
- return (0);
-}
-static void MoxaSetFifo(int port, int enable)
+static void MoxaSetFifo(struct moxa_port *port, int enable)
{
- void __iomem *ofsAddr = moxa_ports[port].tableAddr;
+ void __iomem *ofsAddr = port->tableAddr;
if (!enable) {
moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
diff --git a/drivers/char/moxa.h b/drivers/char/moxa.h
new file mode 100644
index 00000000000..87d16ce57be
--- /dev/null
+++ b/drivers/char/moxa.h
@@ -0,0 +1,304 @@
+#ifndef MOXA_H_FILE
+#define MOXA_H_FILE
+
+#define MOXA 0x400
+#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
+#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_IOQUEUE (MOXA + 27)
+#define MOXA_FLUSH_QUEUE (MOXA + 28)
+#define MOXA_GETMSTATUS (MOXA + 65)
+
+/*
+ * System Configuration
+ */
+
+#define Magic_code 0x404
+
+/*
+ * for C218 BIOS initialization
+ */
+#define C218_ConfBase 0x800
+#define C218_status (C218_ConfBase + 0) /* BIOS running status */
+#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
+#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
+#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
+#define C218check_sum (C218_ConfBase + 8) /* BYTE */
+#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
+#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
+#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
+#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
+#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
+
+#define C218_LoadBuf 0x0F00
+#define C218_KeyCode 0x218
+#define CP204J_KeyCode 0x204
+
+/*
+ * for C320 BIOS initialization
+ */
+#define C320_ConfBase 0x800
+#define C320_LoadBuf 0x0f00
+#define STS_init 0x05 /* for C320_status */
+
+#define C320_status C320_ConfBase + 0 /* BIOS running status */
+#define C320_diag C320_ConfBase + 2 /* diagnostic status */
+#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
+#define C320DLoad_len C320_ConfBase + 6 /* WORD */
+#define C320check_sum C320_ConfBase + 8 /* WORD */
+#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
+#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
+#define C320UART_no C320_ConfBase + 0x0e /* WORD */
+
+#define C320_KeyCode 0x320
+
+#define FixPage_addr 0x0000 /* starting addr of static page */
+#define DynPage_addr 0x2000 /* starting addr of dynamic page */
+#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
+#define Control_reg 0x1ff0 /* select page and reset control */
+#define HW_reset 0x80
+
+/*
+ * Function Codes
+ */
+#define FC_CardReset 0x80
+#define FC_ChannelReset 1 /* C320 firmware not supported */
+#define FC_EnableCH 2
+#define FC_DisableCH 3
+#define FC_SetParam 4
+#define FC_SetMode 5
+#define FC_SetRate 6
+#define FC_LineControl 7
+#define FC_LineStatus 8
+#define FC_XmitControl 9
+#define FC_FlushQueue 10
+#define FC_SendBreak 11
+#define FC_StopBreak 12
+#define FC_LoopbackON 13
+#define FC_LoopbackOFF 14
+#define FC_ClrIrqTable 15
+#define FC_SendXon 16
+#define FC_SetTermIrq 17 /* C320 firmware not supported */
+#define FC_SetCntIrq 18 /* C320 firmware not supported */
+#define FC_SetBreakIrq 19
+#define FC_SetLineIrq 20
+#define FC_SetFlowCtl 21
+#define FC_GenIrq 22
+#define FC_InCD180 23
+#define FC_OutCD180 24
+#define FC_InUARTreg 23
+#define FC_OutUARTreg 24
+#define FC_SetXonXoff 25
+#define FC_OutCD180CCR 26
+#define FC_ExtIQueue 27
+#define FC_ExtOQueue 28
+#define FC_ClrLineIrq 29
+#define FC_HWFlowCtl 30
+#define FC_GetClockRate 35
+#define FC_SetBaud 36
+#define FC_SetDataMode 41
+#define FC_GetCCSR 43
+#define FC_GetDataError 45
+#define FC_RxControl 50
+#define FC_ImmSend 51
+#define FC_SetXonState 52
+#define FC_SetXoffState 53
+#define FC_SetRxFIFOTrig 54
+#define FC_SetTxFIFOCnt 55
+#define FC_UnixRate 56
+#define FC_UnixResetTimer 57
+
+#define RxFIFOTrig1 0
+#define RxFIFOTrig4 1
+#define RxFIFOTrig8 2
+#define RxFIFOTrig14 3
+
+/*
+ * Dual-Ported RAM
+ */
+#define DRAM_global 0
+#define INT_data (DRAM_global + 0)
+#define Config_base (DRAM_global + 0x108)
+
+#define IRQindex (INT_data + 0)
+#define IRQpending (INT_data + 4)
+#define IRQtable (INT_data + 8)
+
+/*
+ * Interrupt Status
+ */
+#define IntrRx 0x01 /* receiver data O.K. */
+#define IntrTx 0x02 /* transmit buffer empty */
+#define IntrFunc 0x04 /* function complete */
+#define IntrBreak 0x08 /* received break */
+#define IntrLine 0x10 /* line status change
+ for transmitter */
+#define IntrIntr 0x20 /* received INTR code */
+#define IntrQuit 0x40 /* received QUIT code */
+#define IntrEOF 0x80 /* received EOF code */
+
+#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
+#define IntrTxTrigger 0x200 /* tx data count below trigger value */
+
+#define Magic_no (Config_base + 0)
+#define Card_model_no (Config_base + 2)
+#define Total_ports (Config_base + 4)
+#define Module_cnt (Config_base + 8)
+#define Module_no (Config_base + 10)
+#define Timer_10ms (Config_base + 14)
+#define Disable_IRQ (Config_base + 20)
+#define TMS320_PORT1 (Config_base + 22)
+#define TMS320_PORT2 (Config_base + 24)
+#define TMS320_CLOCK (Config_base + 26)
+
+/*
+ * DATA BUFFER in DRAM
+ */
+#define Extern_table 0x400 /* Base address of the external table
+ (24 words * 64) total 3K bytes
+ (24 words * 128) total 6K bytes */
+#define Extern_size 0x60 /* 96 bytes */
+#define RXrptr 0x00 /* read pointer for RX buffer */
+#define RXwptr 0x02 /* write pointer for RX buffer */
+#define TXrptr 0x04 /* read pointer for TX buffer */
+#define TXwptr 0x06 /* write pointer for TX buffer */
+#define HostStat 0x08 /* IRQ flag and general flag */
+#define FlagStat 0x0A
+#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
+ /* x x x x | | | | */
+ /* | | | + CTS flow */
+ /* | | +--- RTS flow */
+ /* | +------ TX Xon/Xoff */
+ /* +--------- RX Xon/Xoff */
+#define Break_cnt 0x0E /* received break count */
+#define CD180TXirq 0x10 /* if non-0: enable TX irq */
+#define RX_mask 0x12
+#define TX_mask 0x14
+#define Ofs_rxb 0x16
+#define Ofs_txb 0x18
+#define Page_rxb 0x1A
+#define Page_txb 0x1C
+#define EndPage_rxb 0x1E
+#define EndPage_txb 0x20
+#define Data_error 0x22
+#define RxTrigger 0x28
+#define TxTrigger 0x2a
+
+#define rRXwptr 0x34
+#define Low_water 0x36
+
+#define FuncCode 0x40
+#define FuncArg 0x42
+#define FuncArg1 0x44
+
+#define C218rx_size 0x2000 /* 8K bytes */
+#define C218tx_size 0x8000 /* 32K bytes */
+
+#define C218rx_mask (C218rx_size - 1)
+#define C218tx_mask (C218tx_size - 1)
+
+#define C320p8rx_size 0x2000
+#define C320p8tx_size 0x8000
+#define C320p8rx_mask (C320p8rx_size - 1)
+#define C320p8tx_mask (C320p8tx_size - 1)
+
+#define C320p16rx_size 0x2000
+#define C320p16tx_size 0x4000
+#define C320p16rx_mask (C320p16rx_size - 1)
+#define C320p16tx_mask (C320p16tx_size - 1)
+
+#define C320p24rx_size 0x2000
+#define C320p24tx_size 0x2000
+#define C320p24rx_mask (C320p24rx_size - 1)
+#define C320p24tx_mask (C320p24tx_size - 1)
+
+#define C320p32rx_size 0x1000
+#define C320p32tx_size 0x1000
+#define C320p32rx_mask (C320p32rx_size - 1)
+#define C320p32tx_mask (C320p32tx_size - 1)
+
+#define Page_size 0x2000U
+#define Page_mask (Page_size - 1)
+#define C218rx_spage 3
+#define C218tx_spage 4
+#define C218rx_pageno 1
+#define C218tx_pageno 4
+#define C218buf_pageno 5
+
+#define C320p8rx_spage 3
+#define C320p8tx_spage 4
+#define C320p8rx_pgno 1
+#define C320p8tx_pgno 4
+#define C320p8buf_pgno 5
+
+#define C320p16rx_spage 3
+#define C320p16tx_spage 4
+#define C320p16rx_pgno 1
+#define C320p16tx_pgno 2
+#define C320p16buf_pgno 3
+
+#define C320p24rx_spage 3
+#define C320p24tx_spage 4
+#define C320p24rx_pgno 1
+#define C320p24tx_pgno 1
+#define C320p24buf_pgno 2
+
+#define C320p32rx_spage 3
+#define C320p32tx_ofs C320p32rx_size
+#define C320p32tx_spage 3
+#define C320p32buf_pgno 1
+
+/*
+ * Host Status
+ */
+#define WakeupRx 0x01
+#define WakeupTx 0x02
+#define WakeupBreak 0x08
+#define WakeupLine 0x10
+#define WakeupIntr 0x20
+#define WakeupQuit 0x40
+#define WakeupEOF 0x80 /* used in VTIME control */
+#define WakeupRxTrigger 0x100
+#define WakeupTxTrigger 0x200
+/*
+ * Flag status
+ */
+#define Rx_over 0x01
+#define Xoff_state 0x02
+#define Tx_flowOff 0x04
+#define Tx_enable 0x08
+#define CTS_state 0x10
+#define DSR_state 0x20
+#define DCD_state 0x80
+/*
+ * FlowControl
+ */
+#define CTS_FlowCtl 1
+#define RTS_FlowCtl 2
+#define Tx_FlowCtl 4
+#define Rx_FlowCtl 8
+#define IXM_IXANY 0x10
+
+#define LowWater 128
+
+#define DTR_ON 1
+#define RTS_ON 2
+#define CTS_ON 1
+#define DSR_ON 2
+#define DCD_ON 8
+
+/* mode definition */
+#define MX_CS8 0x03
+#define MX_CS7 0x02
+#define MX_CS6 0x01
+#define MX_CS5 0x00
+
+#define MX_STOP1 0x00
+#define MX_STOP15 0x04
+#define MX_STOP2 0x08
+
+#define MX_PARNONE 0x00
+#define MX_PAREVEN 0x40
+#define MX_PARODD 0xC0
+
+#endif
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 68c2e923469..4b81a85c5b5 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -307,6 +307,200 @@ static unsigned char mxser_msr[MXSER_PORTS + 1];
static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
+static void mxser_enable_must_enchance_mode(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr |= MOXA_MUST_EFR_EFRB_ENABLE;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_disable_must_enchance_mode(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK0;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(value, baseio + MOXA_MUST_XON1_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK0;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(value, baseio + MOXA_MUST_XOFF1_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_fifo_value(struct mxser_port *info)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(info->ioaddr + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR);
+
+ efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK1;
+
+ outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER);
+ outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER);
+ outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER);
+ outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER);
+ outb(oldlcr, info->ioaddr + UART_LCR);
+}
+
+static void mxser_set_must_enum_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK2;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(value, baseio + MOXA_MUST_ENUM_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK2;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ *pId = inb(baseio + MOXA_MUST_HWID_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_MASK;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_enable_must_tx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
+ efr |= MOXA_MUST_EFR_SF_TX1;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_disable_must_tx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_enable_must_rx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
+ efr |= MOXA_MUST_EFR_SF_RX1;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
#ifdef CONFIG_PCI
static int __devinit CheckIsMoxaMust(unsigned long io)
{
@@ -314,16 +508,16 @@ static int __devinit CheckIsMoxaMust(unsigned long io)
int i;
outb(0, io + UART_LCR);
- DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
+ mxser_disable_must_enchance_mode(io);
oldmcr = inb(io + UART_MCR);
outb(0, io + UART_MCR);
- SET_MOXA_MUST_XON1_VALUE(io, 0x11);
+ mxser_set_must_xon1_value(io, 0x11);
if ((hwid = inb(io + UART_MCR)) != 0) {
outb(oldmcr, io + UART_MCR);
return MOXA_OTHER_UART;
}
- GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
+ mxser_get_must_hardware_id(io, &hwid);
for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
if (hwid == Gpci_uart_info[i].type)
return (int)hwid;
@@ -494,10 +688,10 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
} else
quot /= newspd;
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+ mxser_set_must_enum_value(info->ioaddr, quot);
} else
#endif
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
+ mxser_set_must_enum_value(info->ioaddr, 0);
return 0;
}
@@ -553,14 +747,14 @@ static int mxser_change_speed(struct mxser_port *info,
if (info->board->chip_flag) {
fcr = UART_FCR_ENABLE_FIFO;
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
+ mxser_set_must_fifo_value(info);
} else
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
if (info->board->chip_flag) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
+ mxser_set_must_fifo_value(info);
} else {
switch (info->rx_trigger) {
case 1:
@@ -657,17 +851,21 @@ static int mxser_change_speed(struct mxser_port *info,
}
}
if (info->board->chip_flag) {
- SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
- SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+ mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->tty));
+ mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->tty));
if (I_IXON(info->tty)) {
- ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_enable_must_rx_software_flow_control(
+ info->ioaddr);
} else {
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_rx_software_flow_control(
+ info->ioaddr);
}
if (I_IXOFF(info->tty)) {
- ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_enable_must_tx_software_flow_control(
+ info->ioaddr);
} else {
- DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_tx_software_flow_control(
+ info->ioaddr);
}
}
@@ -927,6 +1125,27 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
return 0;
}
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ char fcr;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ fcr = inb(info->ioaddr + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+ outb(fcr, info->ioaddr + UART_FCR);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_wakeup(tty);
+}
+
+
/*
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
@@ -1013,9 +1232,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
mxser_shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
-
+ mxser_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1072,16 +1289,16 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
return total;
}
-static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
if (!info->xmit_buf)
- return;
+ return 0;
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
- return;
+ return 0;
spin_lock_irqsave(&info->slock, flags);
info->xmit_buf[info->xmit_head++] = ch;
@@ -1099,6 +1316,7 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
spin_unlock_irqrestore(&info->slock, flags);
}
}
+ return 1;
}
@@ -1142,26 +1360,6 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
return info->xmit_cnt;
}
-static void mxser_flush_buffer(struct tty_struct *tty)
-{
- struct mxser_port *info = tty->driver_data;
- char fcr;
- unsigned long flags;
-
-
- spin_lock_irqsave(&info->slock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- fcr = inb(info->ioaddr + UART_FCR);
- outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
- info->ioaddr + UART_FCR);
- outb(fcr, info->ioaddr + UART_FCR);
-
- spin_unlock_irqrestore(&info->slock, flags);
-
- tty_wakeup(tty);
-}
-
/*
* ------------------------------------------------------------
* friends of mxser_ioctl()
@@ -1460,6 +1658,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
struct mxser_port *port;
int result, status;
unsigned int i, j;
+ int ret = 0;
switch (cmd) {
case MOXA_GET_MAJOR:
@@ -1467,18 +1666,21 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
case MOXA_CHKPORTENABLE:
result = 0;
-
+ lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
if (mxser_boards[i].ports[j].ioaddr)
result |= (1 << i);
-
+ unlock_kernel();
return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
+ lock_kernel();
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ unlock_kernel();
+ return ret;
case MOXA_GETMSTATUS:
+ lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
@@ -1515,6 +1717,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
else
GMStatus[i].cts = 0;
}
+ unlock_kernel();
if (copy_to_user(argp, GMStatus,
sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
@@ -1524,7 +1727,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
unsigned long opmode;
unsigned cflag, iflag;
- for (i = 0; i < MXSER_BOARDS; i++)
+ lock_kernel();
+ for (i = 0; i < MXSER_BOARDS; i++) {
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
if (!port->ioaddr)
@@ -1589,13 +1793,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
mon_data_ext.iftype[i] = opmode;
}
- if (copy_to_user(argp, &mon_data_ext,
- sizeof(mon_data_ext)))
- return -EFAULT;
-
- return 0;
-
- } default:
+ }
+ unlock_kernel();
+ if (copy_to_user(argp, &mon_data_ext,
+ sizeof(mon_data_ext)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
return -ENOIOCTLCMD;
}
return 0;
@@ -1651,16 +1856,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
opmode != RS422_MODE &&
opmode != RS485_4WIRE_MODE)
return -EFAULT;
+ lock_kernel();
mask = ModeMask[p];
shiftbit = p * 2;
val = inb(info->opmode_ioaddr);
val &= mask;
val |= (opmode << shiftbit);
outb(val, info->opmode_ioaddr);
+ unlock_kernel();
} else {
+ lock_kernel();
shiftbit = p * 2;
opmode = inb(info->opmode_ioaddr) >> shiftbit;
opmode &= OP_MODE_MASK;
+ unlock_kernel();
if (put_user(opmode, (int __user *)argp))
return -EFAULT;
}
@@ -1687,19 +1896,18 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
tty_wait_until_sent(tty, 0);
mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
return 0;
- case TIOCGSOFTCAR:
- return put_user(!!C_CLOCAL(tty), (unsigned long __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
- return mxser_get_serial_info(info, argp);
+ lock_kernel();
+ retval = mxser_get_serial_info(info, argp);
+ unlock_kernel();
+ return retval;
case TIOCSSERIAL:
- return mxser_set_serial_info(info, argp);
+ lock_kernel();
+ retval = mxser_set_serial_info(info, argp);
+ unlock_kernel();
+ return retval;
case TIOCSERGETLSR: /* Get line status register */
- return mxser_get_lsr_info(info, argp);
+ return mxser_get_lsr_info(info, argp);
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -1746,24 +1954,27 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
case MOXA_HighSpeedOn:
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
case MOXA_SDS_RSTICOUNTER:
+ lock_kernel();
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
+ unlock_kernel();
return 0;
case MOXA_ASPP_OQUEUE:{
int len, lsr;
+ lock_kernel();
len = mxser_chars_in_buffer(tty);
-
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
-
len += (lsr ? 0 : 1);
+ unlock_kernel();
return put_user(len, (int __user *)argp);
}
case MOXA_ASPP_MON: {
int mcr, status;
+ lock_kernel();
status = mxser_get_msr(info->ioaddr, 1, tty->index);
mxser_check_modem_status(info, status);
@@ -1782,7 +1993,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
+ unlock_kernel();
if (copy_to_user(argp, &info->mon_data,
sizeof(struct mxser_mon)))
return -EFAULT;
@@ -1925,7 +2136,8 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
if (info->board->chip_flag) {
spin_lock_irqsave(&info->slock, flags);
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_rx_software_flow_control(
+ info->ioaddr);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -1979,6 +2191,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
+ lock_kernel();
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
@@ -1990,6 +2203,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
@@ -2342,7 +2556,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
/* Enhance mode enabled here */
if (brd->chip_flag != MOXA_OTHER_UART)
- ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+ mxser_enable_must_enchance_mode(info->ioaddr);
info->flags = ASYNC_SHARE_IRQ;
info->type = brd->uart_type;
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
index 84417111595..41878a69203 100644
--- a/drivers/char/mxser.h
+++ b/drivers/char/mxser.h
@@ -147,141 +147,4 @@
/* Rx software flow control mask */
#define MOXA_MUST_EFR_SF_RX_MASK 0x03
-#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_FIFO_VALUE(info) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((info)->ioaddr+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
- __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- outb((u8)((info)->rx_high_water), (info)->ioaddr+ \
- MOXA_MUST_RBRTH_REGISTER); \
- outb((u8)((info)->rx_trigger), (info)->ioaddr+ \
- MOXA_MUST_RBRTI_REGISTER); \
- outb((u8)((info)->rx_low_water), (info)->ioaddr+ \
- MOXA_MUST_RBRTL_REGISTER); \
- outb(__oldlcr, (info)->ioaddr+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_TX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_RX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
#endif
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 06803ed5568..a35bfd7ee80 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -342,12 +342,10 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
#endif
/* Flush any pending characters in the driver and discipline. */
-
if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
+ tty->ldisc.flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer (tty);
+ tty_driver_flush_buffer(tty);
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
@@ -399,7 +397,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* Send the next block of data to device */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = tty->driver->write(tty, tbuf->buf, tbuf->count);
+ actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
/* rollback was possible and has been done */
if (actual == -ERESTARTSYS) {
@@ -578,26 +576,36 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
return -EFAULT;
}
+ lock_kernel();
+
for (;;) {
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+ unlock_kernel();
return -EIO;
+ }
n_hdlc = tty2n_hdlc (tty);
if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
- tty != n_hdlc->tty)
+ tty != n_hdlc->tty) {
+ unlock_kernel();
return 0;
+ }
rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
if (rbuf)
break;
/* no data */
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK) {
+ unlock_kernel();
return -EAGAIN;
+ }
interruptible_sleep_on (&tty->read_wait);
- if (signal_pending(current))
+ if (signal_pending(current)) {
+ unlock_kernel();
return -EINTR;
+ }
}
if (rbuf->count > nr)
@@ -618,7 +626,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
kfree(rbuf);
else
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-
+ unlock_kernel();
return ret;
} /* end of n_hdlc_tty_read() */
@@ -661,6 +669,8 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
count = maxframe;
}
+ lock_kernel();
+
add_wait_queue(&tty->write_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -695,7 +705,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
n_hdlc_send_frames(n_hdlc,tty);
}
-
+ unlock_kernel();
return error;
} /* end of n_hdlc_tty_write() */
@@ -740,8 +750,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
case TIOCOUTQ:
/* get the pending tx byte count in the driver */
- count = tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0;
+ count = tty_chars_in_buffer(tty);
/* add size of next output frame in queue */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
if (n_hdlc->tx_buf_list.head)
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 6b918b80f73..90216906233 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -376,8 +376,9 @@ static void put_char(struct r3964_info *pInfo, unsigned char ch)
if (tty == NULL)
return;
- if (tty->driver->put_char) {
- tty->driver->put_char(tty, ch);
+ /* FIXME: put_char should not be called from an IRQ */
+ if (tty->ops->put_char) {
+ tty->ops->put_char(tty, ch);
}
pInfo->bcc ^= ch;
}
@@ -386,12 +387,9 @@ static void flush(struct r3964_info *pInfo)
{
struct tty_struct *tty = pInfo->tty;
- if (tty == NULL)
+ if (tty == NULL || tty->ops->flush_chars == NULL)
return;
-
- if (tty->driver->flush_chars) {
- tty->driver->flush_chars(tty);
- }
+ tty->ops->flush_chars(tty);
}
static void trigger_transmit(struct r3964_info *pInfo)
@@ -449,12 +447,11 @@ static void transmit_block(struct r3964_info *pInfo)
struct r3964_block_header *pBlock = pInfo->tx_first;
int room = 0;
- if ((tty == NULL) || (pBlock == NULL)) {
+ if (tty == NULL || pBlock == NULL) {
return;
}
- if (tty->driver->write_room)
- room = tty->driver->write_room(tty);
+ room = tty_write_room(tty);
TRACE_PS("transmit_block %p, room %d, length %d",
pBlock, room, pBlock->length);
@@ -1075,12 +1072,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
+ lock_kernel();
+
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
pMsg = remove_msg(pInfo, pClient);
if (pMsg == NULL) {
/* no messages available. */
if (file->f_flags & O_NONBLOCK) {
+ unlock_kernel();
return -EAGAIN;
}
/* block until there is a message: */
@@ -1090,8 +1090,10 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
/* If we still haven't got a message, we must have been signalled */
- if (!pMsg)
+ if (!pMsg) {
+ unlock_kernel();
return -EINTR;
+ }
/* deliver msg to client process: */
theMsg.msg_id = pMsg->msg_id;
@@ -1102,12 +1104,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
kfree(pMsg);
TRACE_M("r3964_read - msg kfree %p", pMsg);
- if (copy_to_user(buf, &theMsg, count))
+ if (copy_to_user(buf, &theMsg, count)) {
+ unlock_kernel();
return -EFAULT;
+ }
TRACE_PS("read - return %d", count);
return count;
}
+ unlock_kernel();
return -EPERM;
}
@@ -1156,6 +1161,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
+ lock_kernel();
+
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
pHeader->owner = pClient;
@@ -1173,6 +1180,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
+ unlock_kernel();
+
return 0;
}
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 0c09409fa45..19105ec203f 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -147,10 +147,8 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty)
static void check_unthrottle(struct tty_struct *tty)
{
- if (tty->count &&
- test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ if (tty->count)
+ tty_unthrottle(tty);
}
/**
@@ -183,22 +181,24 @@ static void reset_buffer_flags(struct tty_struct *tty)
* at hangup) or when the N_TTY line discipline internally has to
* clean the pending queue (for example some signals).
*
- * FIXME: tty->ctrl_status is not spinlocked and relies on
- * lock_kernel() still.
+ * Locking: ctrl_lock
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
{
+ unsigned long flags;
/* clear everything and unthrottle the driver */
reset_buffer_flags(tty);
if (!tty->link)
return;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
}
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
/**
@@ -264,17 +264,18 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty)
* relevant in the world today. If you ever need them, add them here.
*
* Called from both the receive and transmit sides and can be called
- * re-entrantly. Relies on lock_kernel() still.
+ * re-entrantly. Relies on lock_kernel() for tty->column state.
*/
static int opost(unsigned char c, struct tty_struct *tty)
{
int space, spaces;
- space = tty->driver->write_room(tty);
+ space = tty_write_room(tty);
if (!space)
return -1;
+ lock_kernel();
if (O_OPOST(tty)) {
switch (c) {
case '\n':
@@ -283,7 +284,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
if (O_ONLCR(tty)) {
if (space < 2)
return -1;
- tty->driver->put_char(tty, '\r');
+ tty_put_char(tty, '\r');
tty->column = 0;
}
tty->canon_column = tty->column;
@@ -305,7 +306,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
if (space < spaces)
return -1;
tty->column += spaces;
- tty->driver->write(tty, " ", spaces);
+ tty->ops->write(tty, " ", spaces);
return 0;
}
tty->column += spaces;
@@ -322,7 +323,8 @@ static int opost(unsigned char c, struct tty_struct *tty)
break;
}
}
- tty->driver->put_char(tty, c);
+ tty_put_char(tty, c);
+ unlock_kernel();
return 0;
}
@@ -337,7 +339,8 @@ static int opost(unsigned char c, struct tty_struct *tty)
* the simple cases normally found and helps to generate blocks of
* symbols for the console driver and thus improve performance.
*
- * Called from write_chan under the tty layer write lock.
+ * Called from write_chan under the tty layer write lock. Relies
+ * on lock_kernel for the tty->column state.
*/
static ssize_t opost_block(struct tty_struct *tty,
@@ -347,12 +350,13 @@ static ssize_t opost_block(struct tty_struct *tty,
int i;
const unsigned char *cp;
- space = tty->driver->write_room(tty);
+ space = tty_write_room(tty);
if (!space)
return 0;
if (nr > space)
nr = space;
+ lock_kernel();
for (i = 0, cp = buf; i < nr; i++, cp++) {
switch (*cp) {
case '\n':
@@ -384,27 +388,15 @@ static ssize_t opost_block(struct tty_struct *tty,
}
}
break_out:
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
- i = tty->driver->write(tty, buf, i);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
+ i = tty->ops->write(tty, buf, i);
+ unlock_kernel();
return i;
}
/**
- * put_char - write character to driver
- * @c: character (or part of unicode symbol)
- * @tty: terminal device
- *
- * Queue a byte to the driver layer for output
- */
-
-static inline void put_char(unsigned char c, struct tty_struct *tty)
-{
- tty->driver->put_char(tty, c);
-}
-
-/**
* echo_char - echo characters
* @c: unicode byte to echo
* @tty: terminal device
@@ -416,8 +408,8 @@ static inline void put_char(unsigned char c, struct tty_struct *tty)
static void echo_char(unsigned char c, struct tty_struct *tty)
{
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
- put_char('^', tty);
- put_char(c ^ 0100, tty);
+ tty_put_char(tty, '^');
+ tty_put_char(tty, c ^ 0100);
tty->column += 2;
} else
opost(c, tty);
@@ -426,7 +418,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
static inline void finish_erasing(struct tty_struct *tty)
{
if (tty->erasing) {
- put_char('/', tty);
+ tty_put_char(tty, '/');
tty->column++;
tty->erasing = 0;
}
@@ -510,7 +502,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!tty->erasing) {
- put_char('\\', tty);
+ tty_put_char(tty, '\\');
tty->column++;
tty->erasing = 1;
}
@@ -518,7 +510,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
echo_char(c, tty);
while (--cnt > 0) {
head = (head+1) & (N_TTY_BUF_SIZE-1);
- put_char(tty->read_buf[head], tty);
+ tty_put_char(tty, tty->read_buf[head]);
}
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
@@ -546,22 +538,22 @@ static void eraser(unsigned char c, struct tty_struct *tty)
/* Now backup to that column. */
while (tty->column > col) {
/* Can't use opost here. */
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
- put_char('\b', tty);
- put_char(' ', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
+ tty_put_char(tty, ' ');
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
- put_char('\b', tty);
- put_char(' ', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
+ tty_put_char(tty, ' ');
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
@@ -592,8 +584,7 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
}
}
@@ -701,7 +692,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
- c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+ c == INTR_CHAR(tty) || c == QUIT_CHAR(tty) || c == SUSP_CHAR(tty)))
start_tty(tty);
if (tty->closing) {
@@ -725,7 +716,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
tty->lnext = 0;
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
- put_char('\a', tty); /* beep if no space */
+ tty_put_char(tty, '\a'); /* beep if no space */
return;
}
/* Record the column of first canon char. */
@@ -739,13 +730,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
return;
}
- if (c == '\r') {
- if (I_IGNCR(tty))
- return;
- if (I_ICRNL(tty))
- c = '\n';
- } else if (c == '\n' && I_INLCR(tty))
- c = '\r';
if (I_IXON(tty)) {
if (c == START_CHAR(tty)) {
start_tty(tty);
@@ -756,6 +740,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
return;
}
}
+
if (L_ISIG(tty)) {
int signal;
signal = SIGINT;
@@ -775,8 +760,7 @@ send_signal:
*/
if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
}
if (L_ECHO(tty))
echo_char(c, tty);
@@ -785,6 +769,15 @@ send_signal:
return;
}
}
+
+ if (c == '\r') {
+ if (I_IGNCR(tty))
+ return;
+ if (I_ICRNL(tty))
+ c = '\n';
+ } else if (c == '\n' && I_INLCR(tty))
+ c = '\r';
+
if (tty->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
@@ -796,8 +789,8 @@ send_signal:
if (L_ECHO(tty)) {
finish_erasing(tty);
if (L_ECHOCTL(tty)) {
- put_char('^', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '^');
+ tty_put_char(tty, '\b');
}
}
return;
@@ -818,7 +811,7 @@ send_signal:
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
- put_char('\a', tty);
+ tty_put_char(tty, '\a');
opost('\n', tty);
}
goto handle_newline;
@@ -836,7 +829,7 @@ send_signal:
*/
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
- put_char('\a', tty);
+ tty_put_char(tty, '\a');
/* Record the column of first canon char. */
if (tty->canon_head == tty->read_head)
tty->canon_column = tty->column;
@@ -866,7 +859,7 @@ handle_newline:
finish_erasing(tty);
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
- put_char('\a', tty); /* beep if no space */
+ tty_put_char(tty, '\a'); /* beep if no space */
return;
}
if (c == '\n')
@@ -970,8 +963,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
break;
}
}
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
}
n_tty_set_room(tty);
@@ -987,12 +980,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE) {
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->throttle)
- tty->driver->throttle(tty);
- }
+ if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+ tty_throttle(tty);
}
int is_ignored(int sig)
@@ -1076,6 +1065,9 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
tty->real_raw = 0;
}
n_tty_set_room(tty);
+ /* The termios change make the tty ready for I/O */
+ wake_up_interruptible(&tty->write_wait);
+ wake_up_interruptible(&tty->read_wait);
}
/**
@@ -1194,6 +1186,11 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
* Perform job control management checks on this file/tty descriptor
* and if appropriate send any needed signals and return a negative
* error code if action should be taken.
+ *
+ * FIXME:
+ * Locking: None - redirected write test is safe, testing
+ * current->signal should possibly lock current->sighand
+ * pgrp locking ?
*/
static int job_control(struct tty_struct *tty, struct file *file)
@@ -1246,6 +1243,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
ssize_t size;
long timeout;
unsigned long flags;
+ int packet;
do_it_again:
@@ -1289,16 +1287,19 @@ do_it_again:
if (mutex_lock_interruptible(&tty->atomic_read_lock))
return -ERESTARTSYS;
}
+ packet = tty->packet;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
/* First test for status change. */
- if (tty->packet && tty->link->ctrl_status) {
+ if (packet && tty->link->ctrl_status) {
unsigned char cs;
if (b != buf)
break;
+ spin_lock_irqsave(&tty->link->ctrl_lock, flags);
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
+ spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
if (tty_put_user(tty, cs, b++)) {
retval = -EFAULT;
b--;
@@ -1333,6 +1334,7 @@ do_it_again:
retval = -ERESTARTSYS;
break;
}
+ /* FIXME: does n_tty_set_room need locking ? */
n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
continue;
@@ -1340,7 +1342,7 @@ do_it_again:
__set_current_state(TASK_RUNNING);
/* Deal with packet mode. */
- if (tty->packet && b == buf) {
+ if (packet && b == buf) {
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
retval = -EFAULT;
b--;
@@ -1388,6 +1390,8 @@ do_it_again:
break;
} else {
int uncopied;
+ /* The copy function takes the read lock and handles
+ locking internally for this case */
uncopied = copy_from_read_buf(tty, &b, &nr);
uncopied += copy_from_read_buf(tty, &b, &nr);
if (uncopied) {
@@ -1429,7 +1433,6 @@ do_it_again:
goto do_it_again;
n_tty_set_room(tty);
-
return retval;
}
@@ -1492,11 +1495,11 @@ static ssize_t write_chan(struct tty_struct *tty, struct file *file,
break;
b++; nr--;
}
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
} else {
while (nr > 0) {
- c = tty->driver->write(tty, b, nr);
+ c = tty->ops->write(tty, b, nr);
if (c < 0) {
retval = c;
goto break_out;
@@ -1533,11 +1536,6 @@ break_out:
*
* This code must be sure never to sleep through a hangup.
* Called without the kernel lock held - fine
- *
- * FIXME: if someone changes the VMIN or discipline settings for the
- * terminal while another process is in poll() the poll does not
- * recompute the new limits. Possibly set_termios should issue
- * a read wakeup to fix this bug.
*/
static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
@@ -1561,9 +1559,9 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
else
tty->minimum_to_wake = 1;
}
- if (!tty_is_writelocked(tty) &&
- tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS &&
- tty->driver->write_room(tty) > 0)
+ if (tty->ops->write && !tty_is_writelocked(tty) &&
+ tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
+ tty_write_room(tty) > 0)
mask |= POLLOUT | POLLWRNORM;
return mask;
}
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 6a6843a0a67..66a0f931c66 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -73,7 +73,7 @@ do { \
char tmp[P_BUF_SIZE]; \
snprintf(tmp, sizeof(tmp), ##args); \
printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \
- __FUNCTION__, tmp); \
+ __func__, tmp); \
} while (0)
#define DBG1(args...) D_(0x01, ##args)
@@ -1407,7 +1407,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
/* Find out what card type it is */
nozomi_get_card_type(dc);
- dc->base_addr = ioremap(start, dc->card_type);
+ dc->base_addr = ioremap_nocache(start, dc->card_type);
if (!dc->base_addr) {
dev_err(&pdev->dev, "Unable to map card MMIO\n");
ret = -ENODEV;
@@ -1724,6 +1724,8 @@ static int ntty_tiocmget(struct tty_struct *tty, struct file *file)
const struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
const struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+ /* Note: these could change under us but it is not clear this
+ matters if so */
return (ctrl_ul->RTS ? TIOCM_RTS : 0) |
(ctrl_ul->DTR ? TIOCM_DTR : 0) |
(ctrl_dl->DCD ? TIOCM_CAR : 0) |
@@ -1849,16 +1851,6 @@ static void ntty_throttle(struct tty_struct *tty)
spin_unlock_irqrestore(&dc->spin_mutex, flags);
}
-/* just to discard single character writes */
-static void ntty_put_char(struct tty_struct *tty, unsigned char c)
-{
- /*
- * card does not react correct when we write single chars
- * to the card, so we discard them
- */
- DBG2("PUT CHAR Function: %c", c);
-}
-
/* Returns number of chars in buffer, called by tty layer */
static s32 ntty_chars_in_buffer(struct tty_struct *tty)
{
@@ -1892,7 +1884,6 @@ static const struct tty_operations tty_ops = {
.unthrottle = ntty_unthrottle,
.throttle = ntty_throttle,
.chars_in_buffer = ntty_chars_in_buffer,
- .put_char = ntty_put_char,
.tiocmget = ntty_tiocmget,
.tiocmset = ntty_tiocmset,
};
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 454d7324ba4..4a933d41342 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -53,7 +53,7 @@ module_param(pc_debug, int, 0600);
#define DEBUGP(n, rdr, x, args...) do { \
if (pc_debug >= (n)) \
dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __FUNCTION__ , ## args); \
+ __func__ , ## args); \
} while (0)
#else
#define DEBUGP(n, rdr, x, args...)
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 5f291bf739a..035084c0732 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -47,7 +47,7 @@ module_param(pc_debug, int, 0600);
#define DEBUGP(n, rdr, x, args...) do { \
if (pc_debug >= (n)) \
dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __FUNCTION__ , ##args); \
+ __func__ , ##args); \
} while (0)
#else
#define DEBUGP(n, rdr, x, args...)
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 583356426df..1dd0e992c83 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -503,20 +503,9 @@ static void* mgslpc_get_text_ptr(void)
* The wrappers maintain line discipline references
* while calling into the line discipline.
*
- * ldisc_flush_buffer - flush line discipline receive buffers
* ldisc_receive_buf - pass receive data to line discipline
*/
-static void ldisc_flush_buffer(struct tty_struct *tty)
-{
- struct tty_ldisc *ld = tty_ldisc_ref(tty);
- if (ld) {
- if (ld->flush_buffer)
- ld->flush_buffer(tty);
- tty_ldisc_deref(ld);
- }
-}
-
static void ldisc_receive_buf(struct tty_struct *tty,
const __u8 *data, char *flags, int count)
{
@@ -1556,7 +1545,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
/* Add a character to the transmit buffer
*/
-static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
+static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
@@ -1567,10 +1556,10 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
}
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
- return;
+ return 0;
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
@@ -1583,6 +1572,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
}
spin_unlock_irqrestore(&info->lock,flags);
+ return 1;
}
/* Enable transmitter so remaining characters in the
@@ -2467,10 +2457,9 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
if (info->flags & ASYNC_INITIALIZED)
mgslpc_wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mgslpc_flush_buffer(tty);
- ldisc_flush_buffer(tty);
+ tty_ldisc_flush(tty);
shutdown(info);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 706ff34728f..0a05c038ae6 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -181,6 +181,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user * arg)
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
+ unsigned long flags;
if (!to)
return;
@@ -189,8 +190,10 @@ static void pty_flush_buffer(struct tty_struct *tty)
to->ldisc.flush_buffer(to);
if (to->packet) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
}
@@ -251,6 +254,18 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
module_param(legacy_count, int, 0);
+static const struct tty_operations pty_ops_bsd = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_bsd_ioctl,
+};
+
static void __init legacy_pty_init(void)
{
if (legacy_count <= 0)
@@ -281,7 +296,6 @@ static void __init legacy_pty_init(void)
pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &pty_ops);
- pty_driver->ioctl = pty_bsd_ioctl;
pty_slave_driver->owner = THIS_MODULE;
pty_slave_driver->driver_name = "pty_slave";
@@ -374,6 +388,19 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
+static const struct tty_operations pty_unix98_ops = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_unix98_ioctl
+};
+
+
static void __init unix98_pty_init(void)
{
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
@@ -400,8 +427,7 @@ static void __init unix98_pty_init(void)
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
- tty_set_operations(ptm_driver, &pty_ops);
- ptm_driver->ioctl = pty_unix98_ioctl;
+ tty_set_operations(ptm_driver, &pty_unix98_ops);
pts_driver->owner = THIS_MODULE;
pts_driver->driver_name = "pty_slave";
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
index f4f837f8682..a03a538a3ef 100644
--- a/drivers/char/rio/cirrus.h
+++ b/drivers/char/rio/cirrus.h
@@ -43,83 +43,83 @@
/* Bit fields for particular registers shared with driver */
/* COR1 - driver and RTA */
-#define COR1_ODD 0x80 /* Odd parity */
-#define COR1_EVEN 0x00 /* Even parity */
-#define COR1_NOP 0x00 /* No parity */
-#define COR1_FORCE 0x20 /* Force parity */
-#define COR1_NORMAL 0x40 /* With parity */
-#define COR1_1STOP 0x00 /* 1 stop bit */
-#define COR1_15STOP 0x04 /* 1.5 stop bits */
-#define COR1_2STOP 0x08 /* 2 stop bits */
-#define COR1_5BITS 0x00 /* 5 data bits */
-#define COR1_6BITS 0x01 /* 6 data bits */
-#define COR1_7BITS 0x02 /* 7 data bits */
-#define COR1_8BITS 0x03 /* 8 data bits */
-
-#define COR1_HOST 0xef /* Safe host bits */
+#define RIOC_COR1_ODD 0x80 /* Odd parity */
+#define RIOC_COR1_EVEN 0x00 /* Even parity */
+#define RIOC_COR1_NOP 0x00 /* No parity */
+#define RIOC_COR1_FORCE 0x20 /* Force parity */
+#define RIOC_COR1_NORMAL 0x40 /* With parity */
+#define RIOC_COR1_1STOP 0x00 /* 1 stop bit */
+#define RIOC_COR1_15STOP 0x04 /* 1.5 stop bits */
+#define RIOC_COR1_2STOP 0x08 /* 2 stop bits */
+#define RIOC_COR1_5BITS 0x00 /* 5 data bits */
+#define RIOC_COR1_6BITS 0x01 /* 6 data bits */
+#define RIOC_COR1_7BITS 0x02 /* 7 data bits */
+#define RIOC_COR1_8BITS 0x03 /* 8 data bits */
+
+#define RIOC_COR1_HOST 0xef /* Safe host bits */
/* RTA only */
-#define COR1_CINPCK 0x00 /* Check parity of received characters */
-#define COR1_CNINPCK 0x10 /* Don't check parity */
+#define RIOC_COR1_CINPCK 0x00 /* Check parity of received characters */
+#define RIOC_COR1_CNINPCK 0x10 /* Don't check parity */
/* COR2 bits for both RTA and driver use */
-#define COR2_IXANY 0x80 /* IXANY - any character is XON */
-#define COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
-#define COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
+#define RIOC_COR2_IXANY 0x80 /* IXANY - any character is XON */
+#define RIOC_COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
+#define RIOC_COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
/* Additional driver bits */
-#define COR2_HUPCL 0x20 /* Hang up on close */
-#define COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
-#define COR2_IXOFF 0x01 /* Enable rx software flow control */
-#define COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
+#define RIOC_COR2_HUPCL 0x20 /* Hang up on close */
+#define RIOC_COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
+#define RIOC_COR2_IXOFF 0x01 /* Enable rx software flow control */
+#define RIOC_COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
/* RTA use only */
-#define COR2_ETC 0x20 /* Embedded transmit options */
-#define COR2_LOCAL 0x10 /* Local loopback mode */
-#define COR2_REMOTE 0x08 /* Remote loopback mode */
-#define COR2_HOST 0xc2 /* Safe host bits */
+#define RIOC_COR2_ETC 0x20 /* Embedded transmit options */
+#define RIOC_COR2_LOCAL 0x10 /* Local loopback mode */
+#define RIOC_COR2_REMOTE 0x08 /* Remote loopback mode */
+#define RIOC_COR2_HOST 0xc2 /* Safe host bits */
/* COR3 - RTA use only */
-#define COR3_SCDRNG 0x80 /* Enable special char detect for range */
-#define COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
-#define COR3_FCT 0x20 /* Flow control transparency */
-#define COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
-#define COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
-#define COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
-#define COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
-#define COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
-
-#define COR3_THRESHOLD COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
-
-#define COR3_DEFAULT (COR3_FCT | COR3_THRESHOLD)
+#define RIOC_COR3_SCDRNG 0x80 /* Enable special char detect for range */
+#define RIOC_COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
+#define RIOC_COR3_FCT 0x20 /* Flow control transparency */
+#define RIOC_COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
+#define RIOC_COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
+
+#define RIOC_COR3_THRESHOLD RIOC_COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
+
+#define RIOC_COR3_DEFAULT (RIOC_COR3_FCT | RIOC_COR3_THRESHOLD)
/* Default bits for COR3 */
/* COR4 driver and RTA use */
-#define COR4_IGNCR 0x80 /* Throw away CR's on input */
-#define COR4_ICRNL 0x40 /* Map CR -> NL on input */
-#define COR4_INLCR 0x20 /* Map NL -> CR on input */
-#define COR4_IGNBRK 0x10 /* Ignore Break */
-#define COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
-#define COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
+#define RIOC_COR4_IGNCR 0x80 /* Throw away CR's on input */
+#define RIOC_COR4_ICRNL 0x40 /* Map CR -> NL on input */
+#define RIOC_COR4_INLCR 0x20 /* Map NL -> CR on input */
+#define RIOC_COR4_IGNBRK 0x10 /* Ignore Break */
+#define RIOC_COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
+#define RIOC_COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
/* COR4 driver only */
-#define COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
-#define COR4_PARMRK 0x02 /* PARMRK */
+#define RIOC_COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
+#define RIOC_COR4_PARMRK 0x02 /* PARMRK */
-#define COR4_HOST 0xf8 /* Safe host bits */
+#define RIOC_COR4_HOST 0xf8 /* Safe host bits */
/* COR4 RTA only */
-#define COR4_CIGNPAR 0x02 /* Thrown away bad characters */
-#define COR4_CPARMRK 0x04 /* PARMRK characters */
-#define COR4_CNPARMRK 0x03 /* Don't PARMRK */
+#define RIOC_COR4_CIGNPAR 0x02 /* Thrown away bad characters */
+#define RIOC_COR4_CPARMRK 0x04 /* PARMRK characters */
+#define RIOC_COR4_CNPARMRK 0x03 /* Don't PARMRK */
/* COR5 driver and RTA use */
-#define COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
-#define COR5_LNE 0x40 /* Enable LNEXT processing */
-#define COR5_CMOE 0x20 /* Match good and errored characters */
-#define COR5_ONLCR 0x02 /* NL -> CR NL on output */
-#define COR5_OCRNL 0x01 /* CR -> NL on output */
+#define RIOC_COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
+#define RIOC_COR5_LNE 0x40 /* Enable LNEXT processing */
+#define RIOC_COR5_CMOE 0x20 /* Match good and errored characters */
+#define RIOC_COR5_ONLCR 0x02 /* NL -> CR NL on output */
+#define RIOC_COR5_OCRNL 0x01 /* CR -> NL on output */
/*
** Spare bits - these are not used in the CIRRUS registers, so we use
@@ -128,86 +128,86 @@
/*
** tstop and tbusy indication
*/
-#define COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
-#define COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
/*
** TAB3
*/
-#define COR5_TAB3 0x10 /* TAB3 mode */
+#define RIOC_COR5_TAB3 0x10 /* TAB3 mode */
-#define COR5_HOST 0xc3 /* Safe host bits */
+#define RIOC_COR5_HOST 0xc3 /* Safe host bits */
/* CCSR */
-#define CCSR_TXFLOFF 0x04 /* Tx is xoffed */
+#define RIOC_CCSR_TXFLOFF 0x04 /* Tx is xoffed */
/* MSVR1 */
/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
serial option.
*/
-#define MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
-#define MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
-#define MSVR1_RI 0x20 /* RI */
-#define MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
-#define MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
+#define RIOC_MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
+#define RIOC_MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
+#define RIOC_MSVR1_RI 0x20 /* RI */
+#define RIOC_MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
+#define RIOC_MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
/* Next two used to indicate state of tbusy and tstop to driver */
-#define MSVR1_TSTOP 0x08 /* Set if port flow controlled */
-#define MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
+#define RIOC_MSVR1_TSTOP 0x08 /* Set if port flow controlled */
+#define RIOC_MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
-#define MSVR1_HOST 0xf3 /* The bits the host wants */
+#define RIOC_MSVR1_HOST 0xf3 /* The bits the host wants */
/* Defines for the subscripts of a CONFIG packet */
-#define CONFIG_COR1 1 /* Option register 1 */
-#define CONFIG_COR2 2 /* Option register 2 */
-#define CONFIG_COR4 3 /* Option register 4 */
-#define CONFIG_COR5 4 /* Option register 5 */
-#define CONFIG_TXXON 5 /* Tx XON character */
-#define CONFIG_TXXOFF 6 /* Tx XOFF character */
-#define CONFIG_RXXON 7 /* Rx XON character */
-#define CONFIG_RXXOFF 8 /* Rx XOFF character */
-#define CONFIG_LNEXT 9 /* LNEXT character */
-#define CONFIG_TXBAUD 10 /* Tx baud rate */
-#define CONFIG_RXBAUD 11 /* Rx baud rate */
-
-#define PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
+#define RIOC_CONFIG_COR1 1 /* Option register 1 */
+#define RIOC_CONFIG_COR2 2 /* Option register 2 */
+#define RIOC_CONFIG_COR4 3 /* Option register 4 */
+#define RIOC_CONFIG_COR5 4 /* Option register 5 */
+#define RIOC_CONFIG_TXXON 5 /* Tx XON character */
+#define RIOC_CONFIG_TXXOFF 6 /* Tx XOFF character */
+#define RIOC_CONFIG_RXXON 7 /* Rx XON character */
+#define RIOC_CONFIG_RXXOFF 8 /* Rx XOFF character */
+#define RIOC_CONFIG_LNEXT 9 /* LNEXT character */
+#define RIOC_CONFIG_TXBAUD 10 /* Tx baud rate */
+#define RIOC_CONFIG_RXBAUD 11 /* Rx baud rate */
+
+#define RIOC_PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
be used
*/
-#define OPEN 0x00 /* Open a port */
-#define CONFIG 0x01 /* Configure a port */
-#define MOPEN 0x02 /* Modem open (block for DCD) */
-#define CLOSE 0x03 /* Close a port */
-#define WFLUSH (0x04 | PRE_EMPTIVE) /* Write flush */
-#define RFLUSH (0x05 | PRE_EMPTIVE) /* Read flush */
-#define RESUME (0x06 | PRE_EMPTIVE) /* Resume if xoffed */
-#define SBREAK 0x07 /* Start break */
-#define EBREAK 0x08 /* End break */
-#define SUSPEND (0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
-#define FCLOSE (0x0a | PRE_EMPTIVE) /* Force close */
-#define XPRINT 0x0b /* Xprint packet */
-#define MBIS (0x0c | PRE_EMPTIVE) /* Set modem lines */
-#define MBIC (0x0d | PRE_EMPTIVE) /* Clear modem lines */
-#define MSET (0x0e | PRE_EMPTIVE) /* Set modem lines */
-#define PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
-#define MGET (0x10 | PRE_EMPTIVE) /* Force update of modem status */
-#define MEMDUMP (0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */
-#define READ_REGISTER (0x12 | PRE_EMPTIVE) /* Read CD1400 register (debug) */
+#define RIOC_OPEN 0x00 /* Open a port */
+#define RIOC_CONFIG 0x01 /* Configure a port */
+#define RIOC_MOPEN 0x02 /* Modem open (block for DCD) */
+#define RIOC_CLOSE 0x03 /* Close a port */
+#define RIOC_WFLUSH (0x04 | RIOC_PRE_EMPTIVE) /* Write flush */
+#define RIOC_RFLUSH (0x05 | RIOC_PRE_EMPTIVE) /* Read flush */
+#define RIOC_RESUME (0x06 | RIOC_PRE_EMPTIVE) /* Resume if xoffed */
+#define RIOC_SBREAK 0x07 /* Start break */
+#define RIOC_EBREAK 0x08 /* End break */
+#define RIOC_SUSPEND (0x09 | RIOC_PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
+#define RIOC_FCLOSE (0x0a | RIOC_PRE_EMPTIVE) /* Force close */
+#define RIOC_XPRINT 0x0b /* Xprint packet */
+#define RIOC_MBIS (0x0c | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_MBIC (0x0d | RIOC_PRE_EMPTIVE) /* Clear modem lines */
+#define RIOC_MSET (0x0e | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
+#define RIOC_MGET (0x10 | RIOC_PRE_EMPTIVE) /* Force update of modem status */
+#define RIOC_MEMDUMP (0x11 | RIOC_PRE_EMPTIVE) /* Send back mem from addr supplied */
+#define RIOC_READ_REGISTER (0x12 | RIOC_PRE_EMPTIVE) /* Read CD1400 register (debug) */
/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
use data[4] / data[3] to indicate current state and modem status respectively
*/
-#define COMPLETE (0x20 | PRE_EMPTIVE)
+#define RIOC_COMPLETE (0x20 | RIOC_PRE_EMPTIVE)
/* Command complete */
-#define BREAK_RECEIVED (0x21 | PRE_EMPTIVE)
+#define RIOC_BREAK_RECEIVED (0x21 | RIOC_PRE_EMPTIVE)
/* Break received */
-#define MODEM_STATUS (0x22 | PRE_EMPTIVE)
+#define RIOC_MODEM_STATUS (0x22 | RIOC_PRE_EMPTIVE)
/* Change in modem status */
/* "Command" packet that could go either way - handshake wake-up */
-#define HANDSHAKE (0x23 | PRE_EMPTIVE)
+#define RIOC_HANDSHAKE (0x23 | RIOC_PRE_EMPTIVE)
/* Wake-up to HOST / RTA */
#endif
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 0ce96670f97..412777cd1e6 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -344,7 +344,7 @@ int rio_minor(struct tty_struct *tty)
static int rio_set_real_termios(void *ptr)
{
- return RIOParam((struct Port *) ptr, CONFIG, 1, 1);
+ return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1);
}
@@ -487,7 +487,7 @@ static int rio_get_CD(void *ptr)
int rv;
func_enter();
- rv = (PortP->ModemState & MSVR1_CD) != 0;
+ rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0;
rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
@@ -607,7 +607,8 @@ static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd
rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
rc = -EIO;
} else {
- if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
rc = -EIO;
}
@@ -622,7 +623,8 @@ static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd
l = arg ? arg * 100 : 250;
if (l > 255)
l = 255;
- if (RIOShortCommand(p, PortP, SBREAK, 2, arg ? arg * 100 : 250) == RIO_FAIL) {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2,
+ arg ? arg * 100 : 250) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
rc = -EIO;
}
diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h
index dc3f005614a..7f26cd7c815 100644
--- a/drivers/char/rio/rio_linux.h
+++ b/drivers/char/rio/rio_linux.h
@@ -186,9 +186,9 @@ static inline void *rio_memcpy_fromio(void *dest, void __iomem *source, int n)
#ifdef DEBUG
#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0)
-#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __FUNCTION__)
-#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __FUNCTION__)
-#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__FUNCTION__, port->line)
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __func__)
+#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __func__)
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__func__, port->line)
#else
#define rio_dprintk(f, str...) /* nothing */
#define func_enter()
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index bf36959fc12..7b96e081488 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -417,7 +417,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
PortP = p->RIOPortp[SysPort];
rio_spin_lock_irqsave(&PortP->portSem, flags);
switch (readb(&PktCmdP->Command)) {
- case BREAK_RECEIVED:
+ case RIOC_BREAK_RECEIVED:
rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n");
/* If the current line disc. is not multi-threading and
the current processor is not the default, reset rup_intr
@@ -428,16 +428,16 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
gs_got_break(&PortP->gs);
break;
- case COMPLETE:
+ case RIOC_COMPLETE:
rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts);
subCommand = 1;
switch (readb(&PktCmdP->SubCommand)) {
- case MEMDUMP:
+ case RIOC_MEMDUMP:
rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr));
break;
- case READ_REGISTER:
+ case RIOC_READ_REGISTER:
rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr));
- p->CdRegister = (readb(&PktCmdP->ModemStatus) & MSVR1_HOST);
+ p->CdRegister = (readb(&PktCmdP->ModemStatus) & RIOC_MSVR1_HOST);
break;
default:
subCommand = 0;
@@ -456,14 +456,15 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
rio_dprintk(RIO_DEBUG_CMD, "No change\n");
/* FALLTHROUGH */
- case MODEM_STATUS:
+ case RIOC_MODEM_STATUS:
/*
** Knock out the tbusy and tstop bits, as these are not relevant
** to the check for modem status change (they're just there because
** it's a convenient place to put them!).
*/
ReportedModemStatus = readb(&PktCmdP->ModemStatus);
- if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) {
+ if ((PortP->ModemState & RIOC_MSVR1_HOST) ==
+ (ReportedModemStatus & RIOC_MSVR1_HOST)) {
rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState);
/*
** Update ModemState just in case tbusy or tstop states have
@@ -497,7 +498,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
/*
** Is there a carrier?
*/
- if (PortP->ModemState & MSVR1_CD) {
+ if (PortP->ModemState & RIOC_MSVR1_CD) {
/*
** Has carrier just appeared?
*/
@@ -691,7 +692,7 @@ void RIOPollHostCommands(struct rio_info *p, struct Host *HostP)
*/
rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
FreeMe = RIOCommandRup(p, Rup, HostP, PacketP);
- if (readb(&PacketP->data[5]) == MEMDUMP) {
+ if (readb(&PacketP->data[5]) == RIOC_MEMDUMP) {
rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6])));
rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 32);
}
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index d8eb2bcbe01..d65ceb9a434 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -422,7 +422,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RIOC_RESUME) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -636,7 +637,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
return -ENXIO;
}
PortP = (p->RIOPortp[PortTty.port]);
- RIOParam(PortP, CONFIG, PortP->State & RIO_MODEM, OK_TO_SLEEP);
+ RIOParam(PortP, RIOC_CONFIG, PortP->State & RIO_MODEM,
+ OK_TO_SLEEP);
return retval;
case RIO_SET_PORT_PARAMS:
@@ -1247,7 +1249,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, PortP, MEMDUMP) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, PortP, RIOC_MEMDUMP) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -1313,7 +1315,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, PortP, RIOC_READ_REGISTER) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -1434,50 +1437,50 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
PktCmdP->PhbNum = port;
switch (Cmd) {
- case MEMDUMP:
+ case RIOC_MEMDUMP:
rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p "
"(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
- PktCmdP->SubCommand = MEMDUMP;
+ PktCmdP->SubCommand = RIOC_MEMDUMP;
PktCmdP->SubAddr = SubCmd.Addr;
break;
- case FCLOSE:
+ case RIOC_FCLOSE:
rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n",
CmdBlkP);
break;
- case READ_REGISTER:
+ case RIOC_READ_REGISTER:
rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) "
"command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
- PktCmdP->SubCommand = READ_REGISTER;
+ PktCmdP->SubCommand = RIOC_READ_REGISTER;
PktCmdP->SubAddr = SubCmd.Addr;
break;
- case RESUME:
+ case RIOC_RESUME:
rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n",
CmdBlkP);
break;
- case RFLUSH:
+ case RIOC_RFLUSH:
rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n",
CmdBlkP);
CmdBlkP->PostFuncP = RIORFlushEnable;
break;
- case SUSPEND:
+ case RIOC_SUSPEND:
rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n",
CmdBlkP);
break;
- case MGET:
+ case RIOC_MGET:
rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n",
CmdBlkP);
break;
- case MSET:
- case MBIC:
- case MBIS:
+ case RIOC_MSET:
+ case RIOC_MBIC:
+ case RIOC_MBIS:
CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command "
"blk %p\n", CmdBlkP);
break;
- case WFLUSH:
+ case RIOC_WFLUSH:
/*
** If we have queued up the maximum number of Write flushes
** allowed then we should not bother sending any more to the
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index 4734e26e1cc..ea21686c69a 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -401,9 +401,8 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP)
PortP->InUse = NOT_INUSE;
rio_spin_unlock(&PortP->portSem);
- if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) {
+ if (RIOParam(PortP, RIOC_OPEN, ((PortP->Cor2Copy & (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) == (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL)
continue; /* with next port */
- }
rio_spin_lock(&PortP->portSem);
PortP->MagicFlags &= ~MAGIC_REBOOT;
}
@@ -429,7 +428,7 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP)
*/
PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0];
- writeb(WFLUSH, &PktCmdP->Command);
+ writeb(RIOC_WFLUSH, &PktCmdP->Command);
p = PortP->HostPort % (u16) PORTS_PER_RTA;
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c
index da276ed57b3..4810b845cc2 100644
--- a/drivers/char/rio/rioparam.c
+++ b/drivers/char/rio/rioparam.c
@@ -177,7 +177,7 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (cmd == OPEN) {
+ if (cmd == RIOC_OPEN) {
/*
** If the port is set to store or lock the parameters, and it is
** paramed with OPEN, we want to restore the saved port termio, but
@@ -241,50 +241,50 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
case CS5:
{
rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n");
- Cor1 |= COR1_5BITS;
+ Cor1 |= RIOC_COR1_5BITS;
break;
}
case CS6:
{
rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n");
- Cor1 |= COR1_6BITS;
+ Cor1 |= RIOC_COR1_6BITS;
break;
}
case CS7:
{
rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n");
- Cor1 |= COR1_7BITS;
+ Cor1 |= RIOC_COR1_7BITS;
break;
}
case CS8:
{
rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n");
- Cor1 |= COR1_8BITS;
+ Cor1 |= RIOC_COR1_8BITS;
break;
}
}
if (TtyP->termios->c_cflag & CSTOPB) {
rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n");
- Cor1 |= COR1_2STOP;
+ Cor1 |= RIOC_COR1_2STOP;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n");
- Cor1 |= COR1_1STOP;
+ Cor1 |= RIOC_COR1_1STOP;
}
if (TtyP->termios->c_cflag & PARENB) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n");
- Cor1 |= COR1_NORMAL;
+ Cor1 |= RIOC_COR1_NORMAL;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n");
- Cor1 |= COR1_NOP;
+ Cor1 |= RIOC_COR1_NOP;
}
if (TtyP->termios->c_cflag & PARODD) {
rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n");
- Cor1 |= COR1_ODD;
+ Cor1 |= RIOC_COR1_ODD;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n");
- Cor1 |= COR1_EVEN;
+ Cor1 |= RIOC_COR1_EVEN;
}
/*
@@ -292,11 +292,11 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
*/
if (TtyP->termios->c_iflag & IXON) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n");
- Cor2 |= COR2_IXON;
+ Cor2 |= RIOC_COR2_IXON;
} else {
if (PortP->Config & RIO_IXON) {
rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n");
- Cor2 |= COR2_IXON;
+ Cor2 |= RIOC_COR2_IXON;
} else
rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n");
}
@@ -304,29 +304,29 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
if (TtyP->termios->c_iflag & IXANY) {
if (PortP->Config & RIO_IXANY) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n");
- Cor2 |= COR2_IXANY;
+ Cor2 |= RIOC_COR2_IXANY;
} else
rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n");
}
if (TtyP->termios->c_iflag & IXOFF) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n");
- Cor2 |= COR2_IXOFF;
+ Cor2 |= RIOC_COR2_IXOFF;
}
if (TtyP->termios->c_cflag & HUPCL) {
rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n");
- Cor2 |= COR2_HUPCL;
+ Cor2 |= RIOC_COR2_HUPCL;
}
if (C_CRTSCTS(TtyP)) {
rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n");
- Cor2 |= COR2_CTSFLOW;
- Cor2 |= COR2_RTSFLOW;
+ Cor2 |= RIOC_COR2_CTSFLOW;
+ Cor2 |= RIOC_COR2_RTSFLOW;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n");
- Cor2 &= ~COR2_CTSFLOW;
- Cor2 &= ~COR2_RTSFLOW;
+ Cor2 &= ~RIOC_COR2_CTSFLOW;
+ Cor2 &= ~RIOC_COR2_RTSFLOW;
}
@@ -341,36 +341,36 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
*/
if (TtyP->termios->c_iflag & IGNBRK) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n");
- Cor4 |= COR4_IGNBRK;
+ Cor4 |= RIOC_COR4_IGNBRK;
}
if (!(TtyP->termios->c_iflag & BRKINT)) {
rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n");
- Cor4 |= COR4_NBRKINT;
+ Cor4 |= RIOC_COR4_NBRKINT;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on break condition\n");
}
if (TtyP->termios->c_iflag & INLCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n");
- Cor4 |= COR4_INLCR;
+ Cor4 |= RIOC_COR4_INLCR;
}
if (TtyP->termios->c_iflag & IGNCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n");
- Cor4 |= COR4_IGNCR;
+ Cor4 |= RIOC_COR4_IGNCR;
}
if (TtyP->termios->c_iflag & ICRNL) {
rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n");
- Cor4 |= COR4_ICRNL;
+ Cor4 |= RIOC_COR4_ICRNL;
}
if (TtyP->termios->c_iflag & IGNPAR) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n");
- Cor4 |= COR4_IGNPAR;
+ Cor4 |= RIOC_COR4_IGNPAR;
}
if (TtyP->termios->c_iflag & PARMRK) {
rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n");
- Cor4 |= COR4_PARMRK;
+ Cor4 |= RIOC_COR4_PARMRK;
}
/*
@@ -378,22 +378,22 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
** on reception of a config packet.
** The download code handles the zero baud condition.
*/
- Cor4 |= COR4_RAISEMOD;
+ Cor4 |= RIOC_COR4_RAISEMOD;
/*
** COR 5
*/
- Cor5 = COR5_CMOE;
+ Cor5 = RIOC_COR5_CMOE;
/*
** Set to monitor tbusy/tstop (or not).
*/
if (PortP->MonitorTstate)
- Cor5 |= COR5_TSTATE_ON;
+ Cor5 |= RIOC_COR5_TSTATE_ON;
else
- Cor5 |= COR5_TSTATE_OFF;
+ Cor5 |= RIOC_COR5_TSTATE_OFF;
/*
** Could set LNE here if you wanted LNext processing. SVR4 will use it.
@@ -401,24 +401,24 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
if (TtyP->termios->c_iflag & ISTRIP) {
rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n");
if (!(PortP->State & RIO_TRIAD_MODE)) {
- Cor5 |= COR5_ISTRIP;
+ Cor5 |= RIOC_COR5_ISTRIP;
}
}
if (TtyP->termios->c_oflag & ONLCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_ONLCR;
+ Cor5 |= RIOC_COR5_ONLCR;
}
if (TtyP->termios->c_oflag & OCRNL) {
rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_OCRNL;
+ Cor5 |= RIOC_COR5_OCRNL;
}
if ((TtyP->termios->c_oflag & TABDLY) == TAB3) {
rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_TAB3;
+ Cor5 |= RIOC_COR5_TAB3;
}
/*
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index 1cb8580a161..c99354843be 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -211,7 +211,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n");
if (repeat_this-- <= 0) {
rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
retval = -EINTR;
goto bombout;
}
@@ -264,7 +264,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
here. If I read the docs correctly the "open"
command piggybacks the parameters immediately.
-- REW */
- RIOParam(PortP, OPEN, 1, OK_TO_SLEEP); /* Open the port */
+ RIOParam(PortP, RIOC_OPEN, 1, OK_TO_SLEEP); /* Open the port */
rio_spin_lock_irqsave(&PortP->portSem, flags);
/*
@@ -275,7 +275,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
func_exit();
return -EINTR;
}
@@ -297,7 +297,8 @@ int riotopen(struct tty_struct *tty, struct file *filp)
** insert test for carrier here. -- ???
** I already see that test here. What's the deal? -- REW
*/
- if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) {
+ if ((PortP->gs.tty->termios->c_cflag & CLOCAL) ||
+ (PortP->ModemState & RIOC_MSVR1_CD)) {
rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort);
/*
tp->tm.c_state |= CARR_ON;
@@ -325,7 +326,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
** I think it's OK. -- REW
*/
rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort);
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
/*
tp->tm.c_state &= ~WOPEN;
*/
@@ -416,7 +417,7 @@ int riotclose(void *ptr)
*/
PortP->State &= ~RIO_MOPEN;
PortP->State &= ~RIO_CARR_ON;
- PortP->ModemState &= ~MSVR1_CD;
+ PortP->ModemState &= ~RIOC_MSVR1_CD;
/*
** If the device was open as both a Modem and a tty line
** then we need to wimp out here, as the port has not really
@@ -453,7 +454,7 @@ int riotclose(void *ptr)
if (repeat_this-- <= 0) {
rv = -EINTR;
rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
goto close_end;
}
rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
@@ -492,8 +493,8 @@ int riotclose(void *ptr)
/* Can't call RIOShortCommand with the port locked. */
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
- if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ if (RIOShortCommand(p, PortP, RIOC_CLOSE, 1, 0) == RIO_FAIL) {
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
rio_spin_lock_irqsave(&PortP->portSem, flags);
goto close_end;
}
@@ -503,7 +504,7 @@ int riotclose(void *ptr)
try--;
if (time_after(jiffies, end_time)) {
rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
break;
}
rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN);
@@ -515,14 +516,14 @@ int riotclose(void *ptr)
}
if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
break;
}
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try);
- /* RIOPreemptiveCmd(p, PortP, FCLOSE); */
+ /* RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); */
/*
** 15.10.1998 ARG - ESIL 0761 part fix
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 3f9d0a9ac36..f073c710ab8 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -4,9 +4,9 @@
* Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com)
*
* This code is loosely based on the Linux serial driver, written by
- * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
- * programming info was obtained from various drivers for other OSes
- * (FreeBSD, ISC, etc), but no source code from those drivers were
+ * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
+ * programming info was obtained from various drivers for other OSes
+ * (FreeBSD, ISC, etc), but no source code from those drivers were
* directly included in this driver.
*
*
@@ -33,7 +33,7 @@
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ioport.h>
@@ -49,7 +49,7 @@
#include <linux/tty_flip.h>
#include <linux/spinlock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "riscom8.h"
#include "riscom8_reg.h"
@@ -57,15 +57,15 @@
/* Am I paranoid or not ? ;-) */
#define RISCOM_PARANOIA_CHECK
-/*
- * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals.
+/*
+ * Crazy InteliCom/8 boards sometimes have swapped CTS & DSR signals.
* You can slightly speed up things by #undefing the following option,
- * if you are REALLY sure that your board is correct one.
+ * if you are REALLY sure that your board is correct one.
*/
#define RISCOM_BRAIN_DAMAGED_CTS
-/*
+/*
* The following defines are mostly for testing purposes. But if you need
* some nice reporting in your syslog, you can define them also.
*/
@@ -112,7 +112,7 @@ static unsigned short rc_ioport[] = {
#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
-static inline int rc_paranoia_check(struct riscom_port const * port,
+static int rc_paranoia_check(struct riscom_port const *port,
char *name, const char *routine)
{
#ifdef RISCOM_PARANOIA_CHECK
@@ -134,52 +134,53 @@ static inline int rc_paranoia_check(struct riscom_port const * port,
}
/*
- *
+ *
* Service functions for RISCom/8 driver.
- *
+ *
*/
/* Get board number from pointer */
-static inline int board_No (struct riscom_board const * bp)
+static inline int board_No(struct riscom_board const *bp)
{
return bp - rc_board;
}
/* Get port number from pointer */
-static inline int port_No (struct riscom_port const * port)
+static inline int port_No(struct riscom_port const *port)
{
- return RC_PORT(port - rc_port);
+ return RC_PORT(port - rc_port);
}
/* Get pointer to board from pointer to port */
-static inline struct riscom_board * port_Board(struct riscom_port const * port)
+static inline struct riscom_board *port_Board(struct riscom_port const *port)
{
return &rc_board[RC_BOARD(port - rc_port)];
}
/* Input Byte from CL CD180 register */
-static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg)
+static inline unsigned char rc_in(struct riscom_board const *bp,
+ unsigned short reg)
{
return inb(bp->base + RC_TO_ISA(reg));
}
/* Output Byte to CL CD180 register */
-static inline void rc_out(struct riscom_board const * bp, unsigned short reg,
+static inline void rc_out(struct riscom_board const *bp, unsigned short reg,
unsigned char val)
{
outb(val, bp->base + RC_TO_ISA(reg));
}
/* Wait for Channel Command Register ready */
-static inline void rc_wait_CCR(struct riscom_board const * bp)
+static void rc_wait_CCR(struct riscom_board const *bp)
{
unsigned long delay;
/* FIXME: need something more descriptive then 100000 :) */
- for (delay = 100000; delay; delay--)
+ for (delay = 100000; delay; delay--)
if (!rc_in(bp, CD180_CCR))
return;
-
+
printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -187,11 +188,11 @@ static inline void rc_wait_CCR(struct riscom_board const * bp)
* RISCom/8 probe functions.
*/
-static inline int rc_request_io_range(struct riscom_board * const bp)
+static int rc_request_io_range(struct riscom_board * const bp)
{
int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
+
+ for (i = 0; i < RC_NIOPORT; i++)
if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
"RISCom/8")) {
goto out_release;
@@ -200,42 +201,42 @@ static inline int rc_request_io_range(struct riscom_board * const bp)
out_release:
printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
board_No(bp), bp->base);
- while(--i >= 0)
+ while (--i >= 0)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
return 1;
}
-static inline void rc_release_io_range(struct riscom_board * const bp)
+static void rc_release_io_range(struct riscom_board * const bp)
{
int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
+
+ for (i = 0; i < RC_NIOPORT; i++)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
}
-
+
/* Reset and setup CD180 chip */
-static void __init rc_init_CD180(struct riscom_board const * bp)
+static void __init rc_init_CD180(struct riscom_board const *bp)
{
unsigned long flags;
-
+
spin_lock_irqsave(&riscom_lock, flags);
- rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
- rc_wait_CCR(bp); /* Wait for CCR ready */
- rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
+ rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
+ rc_wait_CCR(bp); /* Wait for CCR ready */
+ rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
spin_unlock_irqrestore(&riscom_lock, flags);
- msleep(50); /* Delay 0.05 sec */
+ msleep(50); /* Delay 0.05 sec */
spin_lock_irqsave(&riscom_lock, flags);
- rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
- rc_out(bp, CD180_GICR, 0); /* Clear all bits */
- rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
- rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */
- rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */
-
+ rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
+ rc_out(bp, CD180_GICR, 0); /* Clear all bits */
+ rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
+ rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for tx intr */
+ rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for rx intr */
+
/* Setting up prescaler. We need 4 ticks per 1 ms */
rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
-
+
spin_unlock_irqrestore(&riscom_lock, flags);
}
@@ -245,12 +246,12 @@ static int __init rc_probe(struct riscom_board *bp)
unsigned char val1, val2;
int irqs = 0;
int retries;
-
+
bp->irq = 0;
if (rc_request_io_range(bp))
return 1;
-
+
/* Are the I/O ports here ? */
rc_out(bp, CD180_PPRL, 0x5a);
outb(0xff, 0x80);
@@ -258,34 +259,34 @@ static int __init rc_probe(struct riscom_board *bp)
rc_out(bp, CD180_PPRL, 0xa5);
outb(0x00, 0x80);
val2 = rc_in(bp, CD180_PPRL);
-
+
if ((val1 != 0x5a) || (val2 != 0xa5)) {
printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
board_No(bp), bp->base);
goto out_release;
}
-
+
/* It's time to find IRQ for this board */
- for (retries = 0; retries < 5 && irqs <= 0; retries++) {
+ for (retries = 0; retries < 5 && irqs <= 0; retries++) {
irqs = probe_irq_on();
- rc_init_CD180(bp); /* Reset CD180 chip */
- rc_out(bp, CD180_CAR, 2); /* Select port 2 */
+ rc_init_CD180(bp); /* Reset CD180 chip */
+ rc_out(bp, CD180_CAR, 2); /* Select port 2 */
rc_wait_CCR(bp);
- rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
- rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */
+ rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
+ rc_out(bp, CD180_IER, IER_TXRDY);/* Enable tx empty intr */
msleep(50);
irqs = probe_irq_off(irqs);
- val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
- val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
- rc_init_CD180(bp); /* Reset CD180 again */
-
+ val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
+ val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
+ rc_init_CD180(bp); /* Reset CD180 again */
+
if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
"found.\n", board_No(bp), bp->base);
goto out_release;
}
}
-
+
if (irqs <= 0) {
printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
"at 0x%03x.\n", board_No(bp), bp->base);
@@ -293,113 +294,112 @@ static int __init rc_probe(struct riscom_board *bp)
}
bp->irq = irqs;
bp->flags |= RC_BOARD_PRESENT;
-
+
printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
"0x%03x, IRQ %d.\n",
board_No(bp),
(rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
bp->base, bp->irq);
-
+
return 0;
out_release:
rc_release_io_range(bp);
return 1;
}
-/*
- *
+/*
+ *
* Interrupt processing routines.
- *
+ *
*/
-static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
- unsigned char const * what)
+static struct riscom_port *rc_get_port(struct riscom_board const *bp,
+ unsigned char const *what)
{
unsigned char channel;
- struct riscom_port * port;
-
+ struct riscom_port *port;
+
channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
if (channel < CD180_NCH) {
port = &rc_port[board_No(bp) * RC_NPORT + channel];
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED)
return port;
- }
}
- printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
+ printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
board_No(bp), what, channel);
return NULL;
}
-static inline void rc_receive_exc(struct riscom_board const * bp)
+static void rc_receive_exc(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char status;
unsigned char ch, flag;
-
- if (!(port = rc_get_port(bp, "Receive")))
+
+ port = rc_get_port(bp, "Receive");
+ if (port == NULL)
return;
tty = port->tty;
-
-#ifdef RC_REPORT_OVERRUN
+
+#ifdef RC_REPORT_OVERRUN
status = rc_in(bp, CD180_RCSR);
if (status & RCSR_OE)
port->overrun++;
status &= port->mark_mask;
-#else
+#else
status = rc_in(bp, CD180_RCSR) & port->mark_mask;
-#endif
+#endif
ch = rc_in(bp, CD180_RDR);
- if (!status) {
+ if (!status)
return;
- }
if (status & RCSR_TOUT) {
printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
- "Hardware problems ?\n",
+ "Hardware problems ?\n",
board_No(bp), port_No(port));
return;
-
+
} else if (status & RCSR_BREAK) {
printk(KERN_INFO "rc%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
flag = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
-
- } else if (status & RCSR_PE)
+
+ } else if (status & RCSR_PE)
flag = TTY_PARITY;
-
- else if (status & RCSR_FE)
+
+ else if (status & RCSR_FE)
flag = TTY_FRAME;
-
- else if (status & RCSR_OE)
+
+ else if (status & RCSR_OE)
flag = TTY_OVERRUN;
-
else
flag = TTY_NORMAL;
-
+
tty_insert_flip_char(tty, ch, flag);
tty_flip_buffer_push(tty);
}
-static inline void rc_receive(struct riscom_board const * bp)
+static void rc_receive(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char count;
-
- if (!(port = rc_get_port(bp, "Receive")))
+
+ port = rc_get_port(bp, "Receive");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
+
count = rc_in(bp, CD180_RDCR);
-
+
#ifdef RC_REPORT_FIFO
port->hits[count > 8 ? 9 : count]++;
-#endif
-
+#endif
+
while (count--) {
if (tty_buffer_request_room(tty, 1) == 0) {
printk(KERN_WARNING "rc%d: port %d: Working around "
@@ -412,26 +412,26 @@ static inline void rc_receive(struct riscom_board const * bp)
tty_flip_buffer_push(tty);
}
-static inline void rc_transmit(struct riscom_board const * bp)
+static void rc_transmit(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char count;
-
-
- if (!(port = rc_get_port(bp, "Transmit")))
+
+ port = rc_get_port(bp, "Transmit");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
- if (port->IER & IER_TXEMPTY) {
+
+ if (port->IER & IER_TXEMPTY) {
/* FIFO drained */
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXEMPTY;
rc_out(bp, CD180_IER, port->IER);
return;
}
-
+
if ((port->xmit_cnt <= 0 && !port->break_length)
|| tty->stopped || tty->hw_stopped) {
rc_out(bp, CD180_CAR, port_No(port));
@@ -439,7 +439,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
rc_out(bp, CD180_IER, port->IER);
return;
}
-
+
if (port->break_length) {
if (port->break_length > 0) {
if (port->COR2 & COR2_ETC) {
@@ -451,7 +451,8 @@ static inline void rc_transmit(struct riscom_board const * bp)
rc_out(bp, CD180_TDR, CD180_C_ESC);
rc_out(bp, CD180_TDR, CD180_C_DELAY);
rc_out(bp, CD180_TDR, count);
- if (!(port->break_length -= count))
+ port->break_length -= count;
+ if (port->break_length == 0)
port->break_length--;
} else {
rc_out(bp, CD180_TDR, CD180_C_ESC);
@@ -463,7 +464,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
}
return;
}
-
+
count = CD180_NFIFO;
do {
rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
@@ -471,7 +472,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
if (--port->xmit_cnt <= 0)
break;
} while (--count > 0);
-
+
if (port->xmit_cnt <= 0) {
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXRDY;
@@ -481,25 +482,26 @@ static inline void rc_transmit(struct riscom_board const * bp)
tty_wakeup(tty);
}
-static inline void rc_check_modem(struct riscom_board const * bp)
+static void rc_check_modem(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char mcr;
-
- if (!(port = rc_get_port(bp, "Modem")))
+
+ port = rc_get_port(bp, "Modem");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
+
mcr = rc_in(bp, CD180_MCR);
- if (mcr & MCR_CDCHG) {
- if (rc_in(bp, CD180_MSVR) & MSVR_CD)
+ if (mcr & MCR_CDCHG) {
+ if (rc_in(bp, CD180_MSVR) & MSVR_CD)
wake_up_interruptible(&port->open_wait);
else
tty_hangup(tty);
}
-
+
#ifdef RISCOM_BRAIN_DAMAGED_CTS
if (mcr & MCR_CTSCHG) {
if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
@@ -526,13 +528,13 @@ static inline void rc_check_modem(struct riscom_board const * bp)
rc_out(bp, CD180_IER, port->IER);
}
#endif /* RISCOM_BRAIN_DAMAGED_CTS */
-
+
/* Clear change bits */
rc_out(bp, CD180_MCR, 0);
}
/* The main interrupt processing routine */
-static irqreturn_t rc_interrupt(int dummy, void * dev_id)
+static irqreturn_t rc_interrupt(int dummy, void *dev_id)
{
unsigned char status;
unsigned char ack;
@@ -547,13 +549,11 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id)
(RC_BSR_TOUT | RC_BSR_TINT |
RC_BSR_MINT | RC_BSR_RINT))) {
handled = 1;
- if (status & RC_BSR_TOUT)
+ if (status & RC_BSR_TOUT)
printk(KERN_WARNING "rc%d: Got timeout. Hardware "
"error?\n", board_No(bp));
-
else if (status & RC_BSR_RINT) {
ack = rc_in(bp, RC_ACK_RINT);
-
if (ack == (RC_ID | GIVR_IT_RCV))
rc_receive(bp);
else if (ack == (RC_ID | GIVR_IT_REXC))
@@ -562,29 +562,23 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id)
printk(KERN_WARNING "rc%d: Bad receive ack "
"0x%02x.\n",
board_No(bp), ack);
-
} else if (status & RC_BSR_TINT) {
ack = rc_in(bp, RC_ACK_TINT);
-
if (ack == (RC_ID | GIVR_IT_TX))
rc_transmit(bp);
else
printk(KERN_WARNING "rc%d: Bad transmit ack "
"0x%02x.\n",
board_No(bp), ack);
-
} else /* if (status & RC_BSR_MINT) */ {
ack = rc_in(bp, RC_ACK_MINT);
-
- if (ack == (RC_ID | GIVR_IT_MODEM))
+ if (ack == (RC_ID | GIVR_IT_MODEM))
rc_check_modem(bp);
else
printk(KERN_WARNING "rc%d: Bad modem ack "
"0x%02x.\n",
board_No(bp), ack);
-
- }
-
+ }
rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
}
@@ -596,24 +590,24 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id)
*/
/* Called with disabled interrupts */
-static int rc_setup_board(struct riscom_board * bp)
+static int rc_setup_board(struct riscom_board *bp)
{
int error;
- if (bp->flags & RC_BOARD_ACTIVE)
+ if (bp->flags & RC_BOARD_ACTIVE)
return 0;
-
+
error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
"RISCom/8", bp);
- if (error)
+ if (error)
return error;
-
+
rc_out(bp, RC_CTOUT, 0); /* Just in case */
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
-
+
bp->flags |= RC_BOARD_ACTIVE;
-
+
return 0;
}
@@ -622,40 +616,40 @@ static void rc_shutdown_board(struct riscom_board *bp)
{
if (!(bp->flags & RC_BOARD_ACTIVE))
return;
-
+
bp->flags &= ~RC_BOARD_ACTIVE;
-
+
free_irq(bp->irq, NULL);
-
+
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
-
+
}
/*
- * Setting up port characteristics.
+ * Setting up port characteristics.
* Must be called with disabled interrupts
*/
static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
{
- struct tty_struct *tty;
+ struct tty_struct *tty = port->tty;
unsigned long baud;
long tmp;
unsigned char cor1 = 0, cor3 = 0;
unsigned char mcor1 = 0, mcor2 = 0;
-
- if (!(tty = port->tty) || !tty->termios)
+
+ if (tty == NULL || tty->termios == NULL)
return;
port->IER = 0;
port->COR2 = 0;
port->MSVR = MSVR_RTS;
-
+
baud = tty_get_baud_rate(tty);
-
+
/* Select port on the board */
rc_out(bp, CD180_CAR, port_No(port));
-
+
if (!baud) {
/* Drop DTR & exit */
bp->DTR |= (1u << port_No(port));
@@ -666,69 +660,68 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
bp->DTR &= ~(1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
}
-
+
/*
- * Now we must calculate some speed depended things
+ * Now we must calculate some speed depended things
*/
-
+
/* Set baud rate for port */
tmp = (((RC_OSCFREQ + baud/2) / baud +
CD180_TPC/2) / CD180_TPC);
- rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
- rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
- rc_out(bp, CD180_RBPRL, tmp & 0xff);
+ rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
+ rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
+ rc_out(bp, CD180_RBPRL, tmp & 0xff);
rc_out(bp, CD180_TBPRL, tmp & 0xff);
-
+
baud = (baud + 5) / 10; /* Estimated CPS */
-
+
/* Two timer ticks seems enough to wakeup something like SLIP driver */
- tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
+ tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
SERIAL_XMIT_SIZE - 1 : tmp);
-
+
/* Receiver timeout will be transmission time for 1.5 chars */
tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
tmp = (tmp > 0xff) ? 0xff : tmp;
rc_out(bp, CD180_RTPR, tmp);
-
- switch (C_CSIZE(tty)) {
- case CS5:
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
cor1 |= COR1_5BITS;
break;
- case CS6:
+ case CS6:
cor1 |= COR1_6BITS;
break;
- case CS7:
+ case CS7:
cor1 |= COR1_7BITS;
break;
- case CS8:
+ case CS8:
cor1 |= COR1_8BITS;
break;
}
-
- if (C_CSTOPB(tty))
+ if (C_CSTOPB(tty))
cor1 |= COR1_2SB;
-
+
cor1 |= COR1_IGNORE;
- if (C_PARENB(tty)) {
+ if (C_PARENB(tty)) {
cor1 |= COR1_NORMPAR;
- if (C_PARODD(tty))
+ if (C_PARODD(tty))
cor1 |= COR1_ODDP;
- if (I_INPCK(tty))
+ if (I_INPCK(tty))
cor1 &= ~COR1_IGNORE;
}
/* Set marking of some errors */
port->mark_mask = RCSR_OE | RCSR_TOUT;
- if (I_INPCK(tty))
+ if (I_INPCK(tty))
port->mark_mask |= RCSR_FE | RCSR_PE;
- if (I_BRKINT(tty) || I_PARMRK(tty))
+ if (I_BRKINT(tty) || I_PARMRK(tty))
port->mark_mask |= RCSR_BREAK;
- if (I_IGNPAR(tty))
+ if (I_IGNPAR(tty))
port->mark_mask &= ~(RCSR_FE | RCSR_PE);
- if (I_IGNBRK(tty)) {
+ if (I_IGNBRK(tty)) {
port->mark_mask &= ~RCSR_BREAK;
- if (I_IGNPAR(tty))
+ if (I_IGNPAR(tty))
/* Real raw mode. Ignore all */
port->mark_mask &= ~RCSR_OE;
}
@@ -738,7 +731,8 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
port->IER |= IER_DSR | IER_CTS;
mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
- tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
+ tty->hw_stopped = !(rc_in(bp, CD180_MSVR) &
+ (MSVR_CTS|MSVR_DSR));
#else
port->COR2 |= COR2_CTSAE;
#endif
@@ -761,13 +755,13 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
mcor1 |= MCOR1_CDZD;
mcor2 |= MCOR2_CDOD;
}
-
- if (C_CREAD(tty))
+
+ if (C_CREAD(tty))
/* Enable receiver */
port->IER |= IER_RXD;
-
+
/* Set input FIFO size (1-8 bytes) */
- cor3 |= RISCOM_RXFIFO;
+ cor3 |= RISCOM_RXFIFO;
/* Setting up CD180 channel registers */
rc_out(bp, CD180_COR1, cor1);
rc_out(bp, CD180_COR2, port->COR2);
@@ -791,36 +785,30 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
{
unsigned long flags;
-
+
if (port->flags & ASYNC_INITIALIZED)
return 0;
-
+
if (!port->xmit_buf) {
/* We may sleep in get_zeroed_page() */
- unsigned long tmp;
-
- if (!(tmp = get_zeroed_page(GFP_KERNEL)))
+ unsigned long tmp = get_zeroed_page(GFP_KERNEL);
+ if (tmp == 0)
return -ENOMEM;
-
- if (port->xmit_buf) {
+ if (port->xmit_buf)
free_page(tmp);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) tmp;
+ else
+ port->xmit_buf = (unsigned char *) tmp;
}
-
spin_lock_irqsave(&riscom_lock, flags);
- if (port->tty)
+ if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
- if (port->count == 1)
+ if (port->count == 1)
bp->count++;
-
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
rc_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
-
+
spin_unlock_irqrestore(&riscom_lock, flags);
return 0;
}
@@ -829,38 +817,39 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
{
struct tty_struct *tty;
-
- if (!(port->flags & ASYNC_INITIALIZED))
+
+ if (!(port->flags & ASYNC_INITIALIZED))
return;
-
+
#ifdef RC_REPORT_OVERRUN
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
board_No(bp), port_No(port), port->overrun);
-#endif
+#endif
#ifdef RC_REPORT_FIFO
{
int i;
-
+
printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
board_No(bp), port_No(port));
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < 10; i++)
printk("%ld ", port->hits[i]);
- }
printk("].\n");
}
-#endif
+#endif
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
}
- if (!(tty = port->tty) || C_HUPCL(tty)) {
+ tty = port->tty;
+
+ if (tty == NULL || C_HUPCL(tty)) {
/* Drop DTR */
bp->DTR |= (1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
}
-
- /* Select port */
+
+ /* Select port */
rc_out(bp, CD180_CAR, port_No(port));
/* Reset port */
rc_wait_CCR(bp);
@@ -868,28 +857,26 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
/* Disable all interrupts from this port */
port->IER = 0;
rc_out(bp, CD180_IER, port->IER);
-
- if (tty)
+
+ if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
port->flags &= ~ASYNC_INITIALIZED;
-
+
if (--bp->count < 0) {
printk(KERN_INFO "rc%d: rc_shutdown_port: "
"bad board count: %d\n",
board_No(bp), bp->count);
bp->count = 0;
}
-
/*
* If this is the last opened port on the board
* shutdown whole board
*/
- if (!bp->count)
+ if (!bp->count)
rc_shutdown_board(bp);
}
-
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct riscom_port *port)
{
DECLARE_WAITQUEUE(wait, current);
@@ -921,7 +908,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (C_CLOCAL(tty))
+ if (C_CLOCAL(tty))
do_clocal = 1;
/*
@@ -959,7 +946,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
break;
}
if (!(port->flags & ASYNC_CLOSING) &&
@@ -978,50 +965,63 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
port->blocked_open--;
if (retval)
return retval;
-
+
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
-}
+}
-static int rc_open(struct tty_struct * tty, struct file * filp)
+static int rc_open(struct tty_struct *tty, struct file *filp)
{
int board;
int error;
- struct riscom_port * port;
- struct riscom_board * bp;
-
+ struct riscom_port *port;
+ struct riscom_board *bp;
+
board = RC_BOARD(tty->index);
if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
return -ENODEV;
-
+
bp = &rc_board[board];
port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
if (rc_paranoia_check(port, tty->name, "rc_open"))
return -ENODEV;
-
- if ((error = rc_setup_board(bp)))
+
+ error = rc_setup_board(bp);
+ if (error)
return error;
-
+
port->count++;
tty->driver_data = port;
port->tty = tty;
-
- if ((error = rc_setup_port(bp, port)))
- return error;
-
- if ((error = block_til_ready(tty, filp, port)))
- return error;
-
- return 0;
+
+ error = rc_setup_port(bp, port);
+ if (error == 0)
+ error = block_til_ready(tty, filp, port);
+ return error;
}
-static void rc_close(struct tty_struct * tty, struct file * filp)
+static void rc_flush_buffer(struct tty_struct *tty)
+{
+ struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+ unsigned long flags;
+
+ if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
+ return;
+
+ spin_lock_irqsave(&riscom_lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
+ tty_wakeup(tty);
+}
+
+static void rc_close(struct tty_struct *tty, struct file *filp)
{
struct riscom_port *port = (struct riscom_port *) tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
unsigned long timeout;
-
+
if (!port || rc_paranoia_check(port, tty->name, "close"))
return;
@@ -1029,7 +1029,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
if (tty_hung_up_p(filp))
goto out;
-
+
bp = port_Board(port);
if ((tty->count == 1) && (port->count != 1)) {
printk(KERN_INFO "rc%d: rc_close: bad port count;"
@@ -1047,7 +1047,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
goto out;
port->flags |= ASYNC_CLOSING;
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
@@ -1070,24 +1070,22 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
- timeout = jiffies+HZ;
- while(port->IER & IER_TXEMPTY) {
+ timeout = jiffies + HZ;
+ while (port->IER & IER_TXEMPTY) {
msleep_interruptible(jiffies_to_msecs(port->timeout));
if (time_after(jiffies, timeout))
break;
}
}
rc_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rc_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
port->tty = NULL;
if (port->blocked_open) {
- if (port->close_delay) {
+ if (port->close_delay)
msleep_interruptible(jiffies_to_msecs(port->close_delay));
- }
wake_up_interruptible(&port->open_wait);
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
@@ -1097,17 +1095,17 @@ out:
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static int rc_write(struct tty_struct * tty,
+static int rc_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
int c, total = 0;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_write"))
return 0;
-
+
bp = port_Board(port);
if (!tty || !port->xmit_buf)
@@ -1144,38 +1142,41 @@ static int rc_write(struct tty_struct * tty,
return total;
}
-static void rc_put_char(struct tty_struct * tty, unsigned char ch)
+static int rc_put_char(struct tty_struct *tty, unsigned char ch)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (rc_paranoia_check(port, tty->name, "rc_put_char"))
- return;
+ return 0;
if (!tty || !port->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&riscom_lock, flags);
-
+
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
goto out;
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
+ ret = 1;
out:
spin_unlock_irqrestore(&riscom_lock, flags);
+ return ret;
}
-static void rc_flush_chars(struct tty_struct * tty)
+static void rc_flush_chars(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
return;
-
+
if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
!port->xmit_buf)
return;
@@ -1189,11 +1190,11 @@ static void rc_flush_chars(struct tty_struct * tty)
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static int rc_write_room(struct tty_struct * tty)
+static int rc_write_room(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
int ret;
-
+
if (rc_paranoia_check(port, tty->name, "rc_write_room"))
return 0;
@@ -1206,39 +1207,22 @@ static int rc_write_room(struct tty_struct * tty)
static int rc_chars_in_buffer(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
-
+
if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
return 0;
-
- return port->xmit_cnt;
-}
-
-static void rc_flush_buffer(struct tty_struct *tty)
-{
- struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- unsigned long flags;
-
- if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
- return;
-
- spin_lock_irqsave(&riscom_lock, flags);
-
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&riscom_lock, flags);
-
- tty_wakeup(tty);
+ return port->xmit_cnt;
}
static int rc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- struct riscom_board * bp;
+ struct riscom_board *bp;
unsigned char status;
unsigned int result;
unsigned long flags;
- if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+ if (rc_paranoia_check(port, tty->name, __func__))
return -ENODEV;
bp = port_Board(port);
@@ -1266,7 +1250,7 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
unsigned long flags;
struct riscom_board *bp;
- if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+ if (rc_paranoia_check(port, tty->name, __func__))
return -ENODEV;
bp = port_Board(port);
@@ -1292,11 +1276,11 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-static inline void rc_send_break(struct riscom_port * port, unsigned long length)
+static void rc_send_break(struct riscom_port *port, unsigned long length)
{
struct riscom_board *bp = port_Board(port);
unsigned long flags;
-
+
spin_lock_irqsave(&riscom_lock, flags);
port->break_length = RISCOM_TPS / HZ * length;
@@ -1312,17 +1296,17 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static inline int rc_set_serial_info(struct riscom_port * port,
- struct serial_struct __user * newinfo)
+static int rc_set_serial_info(struct riscom_port *port,
+ struct serial_struct __user *newinfo)
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
int change_speed;
-
+
if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
return -EFAULT;
-
-#if 0
+
+#if 0
if ((tmp.irq != bp->irq) ||
(tmp.port != bp->base) ||
(tmp.type != PORT_CIRRUS) ||
@@ -1331,16 +1315,16 @@ static inline int rc_set_serial_info(struct riscom_port * port,
(tmp.xmit_fifo_size != CD180_NFIFO) ||
(tmp.flags & ~RISCOM_LEGAL_FLAGS))
return -EINVAL;
-#endif
-
+#endif
+
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
(tmp.flags & ASYNC_SPD_MASK));
-
+
if (!capable(CAP_SYS_ADMIN)) {
if ((tmp.close_delay != port->close_delay) ||
(tmp.closing_wait != port->closing_wait) ||
((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(tmp.flags & ASYNC_USR_MASK));
@@ -1360,12 +1344,12 @@ static inline int rc_set_serial_info(struct riscom_port * port,
return 0;
}
-static inline int rc_get_serial_info(struct riscom_port * port,
+static int rc_get_serial_info(struct riscom_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
-
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_CIRRUS;
tmp.line = port - rc_port;
@@ -1379,19 +1363,18 @@ static inline int rc_get_serial_info(struct riscom_port * port,
return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
-static int rc_ioctl(struct tty_struct * tty, struct file * filp,
+static int rc_ioctl(struct tty_struct *tty, struct file *filp,
unsigned int cmd, unsigned long arg)
-
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
void __user *argp = (void __user *)arg;
- int retval;
-
+ int retval = 0;
+
if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
return -ENODEV;
-
+
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
return retval;
@@ -1399,45 +1382,40 @@ static int rc_ioctl(struct tty_struct * tty, struct file * filp,
if (!arg)
rc_send_break(port, HZ/4); /* 1/4 second */
break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
break;
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg,(unsigned __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
+ case TIOCGSERIAL:
+ lock_kernel();
+ retval = rc_get_serial_info(port, argp);
+ unlock_kernel();
break;
- case TIOCGSERIAL:
- return rc_get_serial_info(port, argp);
- case TIOCSSERIAL:
- return rc_set_serial_info(port, argp);
- default:
- return -ENOIOCTLCMD;
+ case TIOCSSERIAL:
+ lock_kernel();
+ retval = rc_set_serial_info(port, argp);
+ unlock_kernel();
+ break;
+ default:
+ retval = -ENOIOCTLCMD;
}
- return 0;
+ return retval;
}
-static void rc_throttle(struct tty_struct * tty)
+static void rc_throttle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_throttle"))
return;
-
bp = port_Board(port);
spin_lock_irqsave(&riscom_lock, flags);
-
port->MSVR &= ~MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1446,23 +1424,20 @@ static void rc_throttle(struct tty_struct * tty)
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_unthrottle(struct tty_struct * tty)
+static void rc_unthrottle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
return;
-
bp = port_Board(port);
-
- spin_lock_irqsave(&riscom_lock, flags);
+ spin_lock_irqsave(&riscom_lock, flags);
port->MSVR |= MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1471,62 +1446,58 @@ static void rc_unthrottle(struct tty_struct * tty)
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_stop(struct tty_struct * tty)
+static void rc_stop(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_stop"))
return;
-
+
bp = port_Board(port);
-
- spin_lock_irqsave(&riscom_lock, flags);
+ spin_lock_irqsave(&riscom_lock, flags);
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_start(struct tty_struct * tty)
+static void rc_start(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_start"))
return;
-
+
bp = port_Board(port);
-
+
spin_lock_irqsave(&riscom_lock, flags);
- if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
+ if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_hangup(struct tty_struct * tty)
+static void rc_hangup(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
-
+
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
return;
-
+
bp = port_Board(port);
-
+
rc_shutdown_port(bp, port);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -1534,17 +1505,14 @@ static void rc_hangup(struct tty_struct * tty)
wake_up_interruptible(&port->open_wait);
}
-static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
+static void rc_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
return;
-
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(port_Board(port), port);
@@ -1583,9 +1551,9 @@ static int __init rc_init_drivers(void)
int i;
riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
- if (!riscom_driver)
+ if (!riscom_driver)
return -ENOMEM;
-
+
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
riscom_driver->major = RISCOM8_NORMAL_MAJOR;
@@ -1598,23 +1566,21 @@ static int __init rc_init_drivers(void)
riscom_driver->init_termios.c_ospeed = 9600;
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
- if ((error = tty_register_driver(riscom_driver))) {
+ error = tty_register_driver(riscom_driver);
+ if (error != 0) {
put_tty_driver(riscom_driver);
printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
- "error = %d\n",
- error);
+ "error = %d\n", error);
return 1;
}
-
memset(rc_port, 0, sizeof(rc_port));
for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
rc_port[i].magic = RISCOM8_MAGIC;
- rc_port[i].close_delay = 50 * HZ/100;
- rc_port[i].closing_wait = 3000 * HZ/100;
+ rc_port[i].close_delay = 50 * HZ / 100;
+ rc_port[i].closing_wait = 3000 * HZ / 100;
init_waitqueue_head(&rc_port[i].open_wait);
init_waitqueue_head(&rc_port[i].close_wait);
}
-
return 0;
}
@@ -1627,13 +1593,13 @@ static void rc_release_drivers(void)
#ifndef MODULE
/*
* Called at boot time.
- *
+ *
* You can specify IO base for up to RC_NBOARD cards,
* using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
* Note that there will be no probing at default
* addresses in this case.
*
- */
+ */
static int __init riscom8_setup(char *str)
{
int ints[RC_NBOARD];
@@ -1644,7 +1610,7 @@ static int __init riscom8_setup(char *str)
for (i = 0; i < RC_NBOARD; i++) {
if (i < ints[0])
rc_board[i].base = ints[i+1];
- else
+ else
rc_board[i].base = 0;
}
return 1;
@@ -1659,8 +1625,8 @@ static char banner[] __initdata =
static char no_boards_msg[] __initdata =
KERN_INFO "rc: No RISCom/8 boards detected.\n";
-/*
- * This routine must be called by kernel at boot time
+/*
+ * This routine must be called by kernel at boot time
*/
static int __init riscom8_init(void)
{
@@ -1669,13 +1635,12 @@ static int __init riscom8_init(void)
printk(banner);
- if (rc_init_drivers())
+ if (rc_init_drivers())
return -EIO;
- for (i = 0; i < RC_NBOARD; i++)
- if (rc_board[i].base && !rc_probe(&rc_board[i]))
+ for (i = 0; i < RC_NBOARD; i++)
+ if (rc_board[i].base && !rc_probe(&rc_board[i]))
found++;
-
if (!found) {
rc_release_drivers();
printk(no_boards_msg);
@@ -1702,13 +1667,13 @@ MODULE_LICENSE("GPL");
* by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
*
*/
-static int __init riscom8_init_module (void)
+static int __init riscom8_init_module(void)
{
#ifdef MODULE
int i;
if (iobase || iobase1 || iobase2 || iobase3) {
- for(i = 0; i < RC_NBOARD; i++)
+ for (i = 0; i < RC_NBOARD; i++)
rc_board[i].base = 0;
}
@@ -1724,18 +1689,17 @@ static int __init riscom8_init_module (void)
return riscom8_init();
}
-
-static void __exit riscom8_exit_module (void)
+
+static void __exit riscom8_exit_module(void)
{
int i;
-
+
rc_release_drivers();
- for (i = 0; i < RC_NBOARD; i++)
- if (rc_board[i].flags & RC_BOARD_PRESENT)
+ for (i = 0; i < RC_NBOARD; i++)
+ if (rc_board[i].flags & RC_BOARD_PRESENT)
rc_release_io_range(&rc_board[i]);
-
+
}
module_init(riscom8_init_module);
module_exit(riscom8_exit_module);
-
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index f585bc8579e..743dc80a932 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -449,7 +449,8 @@ static void rp_do_transmit(struct r_port *info)
while (1) {
if (tty->stopped || tty->hw_stopped)
break;
- c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail));
+ c = min(info->xmit_fifo_room, info->xmit_cnt);
+ c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
if (c <= 0 || info->xmit_fifo_room <= 0)
break;
sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
@@ -1433,29 +1434,38 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file,
{
struct r_port *info = (struct r_port *) tty->driver_data;
void __user *argp = (void __user *)arg;
+ int ret = 0;
if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
return -ENXIO;
+ lock_kernel();
+
switch (cmd) {
case RCKP_GET_STRUCT:
if (copy_to_user(argp, info, sizeof (struct r_port)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
case RCKP_GET_CONFIG:
- return get_config(info, argp);
+ ret = get_config(info, argp);
+ break;
case RCKP_SET_CONFIG:
- return set_config(info, argp);
+ ret = set_config(info, argp);
+ break;
case RCKP_GET_PORTS:
- return get_ports(info, argp);
+ ret = get_ports(info, argp);
+ break;
case RCKP_RESET_RM2:
- return reset_rm2(info, argp);
+ ret = reset_rm2(info, argp);
+ break;
case RCKP_GET_VERSION:
- return get_version(info, argp);
+ ret = get_version(info, argp);
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
- return 0;
+ unlock_kernel();
+ return ret;
}
static void rp_send_xchar(struct tty_struct *tty, char ch)
@@ -1575,6 +1585,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
jiffies);
printk(KERN_INFO "cps=%d...\n", info->cps);
#endif
+ lock_kernel();
while (1) {
txcnt = sGetTxCnt(cp);
if (!txcnt) {
@@ -1602,6 +1613,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
__set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
#endif
@@ -1651,14 +1663,14 @@ static void rp_hangup(struct tty_struct *tty)
* writing routines will write directly to transmit FIFO.
* Write buffer and counters protected by spinlocks
*/
-static void rp_put_char(struct tty_struct *tty, unsigned char ch)
+static int rp_put_char(struct tty_struct *tty, unsigned char ch)
{
struct r_port *info = (struct r_port *) tty->driver_data;
CHANNEL_t *cp;
unsigned long flags;
if (rocket_paranoia_check(info, "rp_put_char"))
- return;
+ return 0;
/*
* Grab the port write mutex, locking out other processes that try to
@@ -1687,6 +1699,7 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
}
spin_unlock_irqrestore(&info->slock, flags);
mutex_unlock(&info->write_mtx);
+ return 1;
}
/*
@@ -1749,10 +1762,10 @@ static int rp_write(struct tty_struct *tty,
/* Write remaining data into the port's xmit_buf */
while (1) {
- if (!info->tty) /* Seemingly obligatory check... */
+ if (!info->tty) /* Seemingly obligatory check... */
goto end;
-
- c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head));
+ c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
+ c = min(c, XMIT_BUF_SIZE - info->xmit_head);
if (c <= 0)
break;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index df8cd0ca97e..fd2db07a50f 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1060,7 +1060,7 @@ static void config_setup(struct cyclades_port *info)
} /* config_setup */
-static void cy_put_char(struct tty_struct *tty, unsigned char ch)
+static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
@@ -1070,7 +1070,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
return;
@@ -1078,13 +1078,14 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
local_irq_save(flags);
if (info->xmit_cnt >= PAGE_SIZE - 1) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= PAGE_SIZE - 1;
info->xmit_cnt++;
local_irq_restore(flags);
+ return 1;
} /* cy_put_char */
static void cy_flush_chars(struct tty_struct *tty)
@@ -1539,6 +1540,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
#endif
+ lock_kernel();
+
switch (cmd) {
case CYGETMON:
ret_val = get_mon_info(info, argp);
@@ -1584,18 +1587,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
break;
/* The following commands are incompletely implemented!!! */
- case TIOCGSOFTCAR:
- ret_val =
- put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long __user *)argp);
- break;
- case TIOCSSOFTCAR:
- ret_val = get_user(val, (unsigned long __user *)argp);
- if (ret_val)
- break;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
- break;
case TIOCGSERIAL:
ret_val = get_serial_info(info, argp);
break;
@@ -1605,6 +1596,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
default:
ret_val = -ENOIOCTLCMD;
}
+ unlock_kernel();
#ifdef SERIAL_DEBUG_OTHER
printk("cy_ioctl done\n");
@@ -1683,8 +1675,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
if (info->flags & ASYNC_INITIALIZED)
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ cy_flush_buffer(tty);
tty_ldisc_flush(tty);
info->tty = NULL;
if (info->blocked_open) {
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index b9c1dba6bd0..8fe099a4106 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -80,7 +80,7 @@ scdrv_open(struct inode *inode, struct file *file)
sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
if (sd == NULL) {
printk("%s: couldn't allocate subchannel data\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -90,7 +90,7 @@ scdrv_open(struct inode *inode, struct file *file)
if (sd->sd_subch < 0) {
kfree(sd);
- printk("%s: couldn't allocate subchannel\n", __FUNCTION__);
+ printk("%s: couldn't allocate subchannel\n", __func__);
return -EBUSY;
}
@@ -110,7 +110,7 @@ scdrv_open(struct inode *inode, struct file *file)
if (rv) {
ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
kfree(sd);
- printk("%s: irq request failed (%d)\n", __FUNCTION__, rv);
+ printk("%s: irq request failed (%d)\n", __func__, rv);
return -EBUSY;
}
@@ -215,7 +215,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
*/
if (count < len) {
pr_debug("%s: only accepting %d of %d bytes\n",
- __FUNCTION__, (int) count, len);
+ __func__, (int) count, len);
}
len = min((int) count, len);
if (copy_to_user(buf, sd->sd_rb, len))
@@ -384,7 +384,7 @@ scdrv_init(void)
if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
SYSCTL_BASENAME) < 0) {
printk("%s: failed to register SN system controller device\n",
- __FUNCTION__);
+ __func__);
return -ENODEV;
}
snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
@@ -403,7 +403,7 @@ scdrv_init(void)
GFP_KERNEL);
if (!scd) {
printk("%s: failed to allocate device info"
- "for %s/%s\n", __FUNCTION__,
+ "for %s/%s\n", __func__,
SYSCTL_BASENAME, devname);
continue;
}
@@ -412,7 +412,7 @@ scdrv_init(void)
scd->scd_nasid = cnodeid_to_nasid(cnode);
if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
printk("%s: failed to allocate driver buffer"
- "(%s%s)\n", __FUNCTION__,
+ "(%s%s)\n", __func__,
SYSCTL_BASENAME, devname);
kfree(scd);
continue;
@@ -424,7 +424,7 @@ scdrv_init(void)
("%s: failed to initialize SAL for"
" system controller communication"
" (%s/%s): outdated PROM?\n",
- __FUNCTION__, SYSCTL_BASENAME, devname);
+ __func__, SYSCTL_BASENAME, devname);
kfree(scd);
kfree(salbuf);
continue;
@@ -435,7 +435,7 @@ scdrv_init(void)
if (cdev_add(&scd->scd_cdev, dev, 1)) {
printk("%s: failed to register system"
" controller device (%s%s)\n",
- __FUNCTION__, SYSCTL_BASENAME, devname);
+ __func__, SYSCTL_BASENAME, devname);
kfree(scd);
kfree(salbuf);
continue;
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index 31a7765eaf7..53b3d44f8c0 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -271,7 +271,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
if (event_sd == NULL) {
printk(KERN_WARNING "%s: couldn't allocate subchannel info"
- " for event monitoring\n", __FUNCTION__);
+ " for event monitoring\n", __func__);
return;
}
@@ -285,7 +285,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
if (event_sd->sd_subch < 0) {
kfree(event_sd);
printk(KERN_WARNING "%s: couldn't open event subchannel\n",
- __FUNCTION__);
+ __func__);
return;
}
@@ -295,7 +295,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
"system controller events", event_sd);
if (rv) {
printk(KERN_WARNING "%s: irq request failed (%d)\n",
- __FUNCTION__, rv);
+ __func__, rv);
ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
kfree(event_sd);
return;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index c03ad164c39..58533de5902 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -506,7 +506,7 @@ static struct sonypi_device {
while (--n && (command)) \
udelay(1); \
if (!n && (verbose || !quiet)) \
- printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+ printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \
}
#ifdef CONFIG_ACPI
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 4b5b5b78acb..2ee4d989375 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -131,8 +131,8 @@ static int sx_rxfifo = SPECIALIX_RXFIFO;
#define SX_DEBUG_FIFO 0x0800
-#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
-#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __FUNCTION__)
+#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__func__)
+#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __func__)
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
@@ -874,7 +874,7 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
spin_lock_irqsave(&bp->lock, flags);
- dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
+ dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
if (!(bp->flags & SX_BOARD_ACTIVE)) {
dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", bp->irq);
spin_unlock_irqrestore(&bp->lock, flags);
@@ -1504,6 +1504,27 @@ static int sx_open(struct tty_struct * tty, struct file * filp)
return 0;
}
+static void sx_flush_buffer(struct tty_struct *tty)
+{
+ struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+ unsigned long flags;
+ struct specialix_board * bp;
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+ func_exit();
+ return;
+ }
+
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
+ tty_wakeup(tty);
+
+ func_exit();
+}
static void sx_close(struct tty_struct * tty, struct file * filp)
{
@@ -1597,8 +1618,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
sx_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ sx_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
@@ -1670,7 +1690,7 @@ static int sx_write(struct tty_struct * tty,
}
-static void sx_put_char(struct tty_struct * tty, unsigned char ch)
+static int sx_put_char(struct tty_struct * tty, unsigned char ch)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
@@ -1680,12 +1700,12 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
func_exit();
- return;
+ return 0;
}
dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
if (!port->xmit_buf) {
func_exit();
- return;
+ return 0;
}
bp = port_Board(port);
spin_lock_irqsave(&port->lock, flags);
@@ -1695,7 +1715,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
spin_unlock_irqrestore(&port->lock, flags);
dprintk (SX_DEBUG_TX, "Exit size\n");
func_exit();
- return;
+ return 0;
}
dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
port->xmit_buf[port->xmit_head++] = ch;
@@ -1704,6 +1724,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
spin_unlock_irqrestore(&port->lock, flags);
func_exit();
+ return 1;
}
@@ -1770,28 +1791,6 @@ static int sx_chars_in_buffer(struct tty_struct *tty)
}
-static void sx_flush_buffer(struct tty_struct *tty)
-{
- struct specialix_port *port = (struct specialix_port *)tty->driver_data;
- unsigned long flags;
- struct specialix_board * bp;
-
- func_enter();
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
- func_exit();
- return;
- }
-
- bp = port_Board(port);
- spin_lock_irqsave(&port->lock, flags);
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&port->lock, flags);
- tty_wakeup(tty);
-
- func_exit();
-}
-
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
@@ -1803,7 +1802,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
func_enter();
- if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ if (sx_paranoia_check(port, tty->name, __func__)) {
func_exit();
return -ENODEV;
}
@@ -1845,7 +1844,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
func_enter();
- if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ if (sx_paranoia_check(port, tty->name, __func__)) {
func_exit();
return -ENODEV;
}
@@ -1922,29 +1921,13 @@ static inline int sx_set_serial_info(struct specialix_port * port,
int change_speed;
func_enter();
- /*
- if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) {
- func_exit();
- return -EFAULT;
- }
- */
+
if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
func_enter();
return -EFAULT;
}
-#if 0
- if ((tmp.irq != bp->irq) ||
- (tmp.port != bp->base) ||
- (tmp.type != PORT_CIRRUS) ||
- (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
- (tmp.custom_divisor != 0) ||
- (tmp.xmit_fifo_size != CD186x_NFIFO) ||
- (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
- func_exit();
- return -EINVAL;
- }
-#endif
+ lock_kernel();
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
(tmp.flags & ASYNC_SPD_MASK));
@@ -1956,6 +1939,7 @@ static inline int sx_set_serial_info(struct specialix_port * port,
((tmp.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
func_exit();
+ unlock_kernel();
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1972,6 +1956,7 @@ static inline int sx_set_serial_info(struct specialix_port * port,
sx_change_speed(bp, port);
}
func_exit();
+ unlock_kernel();
return 0;
}
@@ -1984,12 +1969,8 @@ static inline int sx_get_serial_info(struct specialix_port * port,
func_enter();
- /*
- if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
- return -EFAULT;
- */
-
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.type = PORT_CIRRUS;
tmp.line = port - sx_port;
tmp.port = bp->base;
@@ -2000,6 +1981,7 @@ static inline int sx_get_serial_info(struct specialix_port * port,
tmp.closing_wait = port->closing_wait * HZ/100;
tmp.custom_divisor = port->custom_divisor;
tmp.xmit_fifo_size = CD186x_NFIFO;
+ unlock_kernel();
if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
func_exit();
return -EFAULT;
@@ -2045,23 +2027,6 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp,
sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
func_exit();
return 0;
- case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
- func_exit();
- return -EFAULT;
- }
- func_exit();
- return 0;
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp)) {
- func_exit();
- return -EFAULT;
- }
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- func_exit();
- return 0;
case TIOCGSERIAL:
func_exit();
return sx_get_serial_info(port, argp);
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 874aaa08e95..d17be10c5d2 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -875,6 +875,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
timeout = HZ;
tend = jiffies + timeout;
+ lock_kernel();
while (stl_datastate(portp)) {
if (signal_pending(current))
break;
@@ -882,6 +883,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
if (time_after_eq(jiffies, tend))
break;
}
+ unlock_kernel();
}
/*****************************************************************************/
@@ -1273,18 +1275,9 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
rc = 0;
+ lock_kernel();
+
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) argp);
- break;
- case TIOCSSOFTCAR:
- if (get_user(ival, (unsigned int __user *) arg))
- return -EFAULT;
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stl_getserial(portp, argp);
break;
@@ -1308,7 +1301,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
rc = -ENOIOCTLCMD;
break;
}
-
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index a6e1c9ba121..f39f6fd8935 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -384,11 +384,11 @@ static struct real_driver sx_real_driver = {
#define sx_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
-#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__FUNCTION__)
+#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__func__)
+#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__func__)
#define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
- __FUNCTION__, port->line)
+ __func__, port->line)
/*
* Firmware loader driver specific routines
@@ -1574,7 +1574,7 @@ static void sx_close(void *ptr)
sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
port->gs.count);
/*printk("%s SETTING port count to zero: %p count: %d\n",
- __FUNCTION__, port, port->gs.count);
+ __func__, port, port->gs.count);
port->gs.count = 0;*/
}
@@ -1844,6 +1844,7 @@ static void sx_break(struct tty_struct *tty, int flag)
int rv;
func_enter();
+ lock_kernel();
if (flag)
rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
@@ -1852,7 +1853,7 @@ static void sx_break(struct tty_struct *tty, int flag)
if (rv != 1)
printk(KERN_ERR "sx: couldn't send break (%x).\n",
read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
-
+ unlock_kernel();
func_exit();
}
@@ -1888,23 +1889,12 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
int rc;
struct sx_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
- int ival;
/* func_enter2(); */
rc = 0;
+ lock_kernel();
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *)argp);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) {
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- }
- break;
case TIOCGSERIAL:
rc = gs_getserial(&port->gs, argp);
break;
@@ -1915,6 +1905,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
/* func_exit(); */
return rc;
@@ -2549,7 +2540,7 @@ static int __devinit sx_eisa_probe(struct device *dev)
goto err_flag;
}
board->base2 =
- board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+ board->base = ioremap_nocache(board->hw_base, SI2_EISA_WINDOW_LEN);
if (!board->base) {
dev_err(dev, "can't remap memory\n");
goto err_reg;
@@ -2626,7 +2617,7 @@ static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
- rebase = ioremap(hwbase, 0x80);
+ rebase = ioremap_nocache(hwbase, 0x80);
t = readl(rebase + CNTRL_REG_OFFSET);
if (t != CNTRL_REG_GOODVALUE) {
printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
@@ -2770,7 +2761,7 @@ static int __init sx_init(void)
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_sx_reg;
board->flags &= ~SX_BOARD_TYPE;
@@ -2794,7 +2785,7 @@ err_sx_reg:
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_si_reg;
board->flags &= ~SX_BOARD_TYPE;
@@ -2817,7 +2808,7 @@ err_si_reg:
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_si1_reg;
board->flags &= ~SX_BOARD_TYPE;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index fadab1d9510..513b7c2f3e2 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2026,10 +2026,11 @@ static void mgsl_change_params(struct mgsl_struct *info)
*
* Return Value: None
*/
-static void mgsl_put_char(struct tty_struct *tty, unsigned char ch)
+static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
unsigned long flags;
+ int ret;
if ( debug_level >= DEBUG_LEVEL_INFO ) {
printk( "%s(%d):mgsl_put_char(%d) on %s\n",
@@ -2037,23 +2038,23 @@ static void mgsl_put_char(struct tty_struct *tty, unsigned char ch)
}
if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char"))
- return;
+ return 0;
if (!tty || !info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->irq_spinlock,flags);
if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
-
if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= SERIAL_XMIT_SIZE-1;
info->xmit_cnt++;
+ ret = 1;
}
}
-
spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ return ret;
} /* end of mgsl_put_char() */
@@ -2942,6 +2943,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+ int ret;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
@@ -2956,7 +2958,10 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
return -EIO;
}
- return mgsl_ioctl_common(info, cmd, arg);
+ lock_kernel();
+ ret = mgsl_ioctl_common(info, cmd, arg);
+ unlock_kernel();
+ return ret;
}
static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
@@ -3153,8 +3158,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
if (info->flags & ASYNC_INITIALIZED)
mgsl_wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mgsl_flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -3217,7 +3221,8 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
* interval should also be less than the timeout.
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
-
+
+ lock_kernel();
if ( info->params.data_rate ) {
char_time = info->timeout/(32 * 5);
if (!char_time)
@@ -3247,6 +3252,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
}
+ unlock_kernel();
exit:
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4144,7 +4150,8 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
}
info->lcr_mem_requested = true;
- info->memory_base = ioremap(info->phys_memory_base,0x40000);
+ info->memory_base = ioremap_nocache(info->phys_memory_base,
+ 0x40000);
if (!info->memory_base) {
printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -4157,12 +4164,14 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
goto errout;
}
- info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
+ info->lcr_base = ioremap_nocache(info->phys_lcr_base,
+ PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
goto errout;
}
+ info->lcr_base += info->lcr_offset;
} else {
/* claim DMA channel */
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index f3d8d72e5ea..2001b0e52dc 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -151,7 +151,7 @@ static void hangup(struct tty_struct *tty);
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void put_char(struct tty_struct *tty, unsigned char ch);
+static int put_char(struct tty_struct *tty, unsigned char ch);
static void send_xchar(struct tty_struct *tty, char ch);
static void wait_until_sent(struct tty_struct *tty, int timeout);
static int write_room(struct tty_struct *tty);
@@ -771,8 +771,7 @@ static void close(struct tty_struct *tty, struct file *filp)
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(info);
@@ -913,20 +912,24 @@ cleanup:
return ret;
}
-static void put_char(struct tty_struct *tty, unsigned char ch)
+static int put_char(struct tty_struct *tty, unsigned char ch)
{
struct slgt_info *info = tty->driver_data;
unsigned long flags;
+ int ret;
if (sanity_check(info, tty->name, "put_char"))
- return;
+ return 0;
DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active && (info->tx_count < info->max_frame_size))
+ if (!info->tx_active && (info->tx_count < info->max_frame_size)) {
info->tx_buf[info->tx_count++] = ch;
+ ret = 1;
+ }
spin_unlock_irqrestore(&info->lock,flags);
+ return ret;
}
static void send_xchar(struct tty_struct *tty, char ch)
@@ -967,6 +970,8 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
+ lock_kernel();
+
if (info->params.data_rate) {
char_time = info->timeout/(32 * 5);
if (!char_time)
@@ -984,6 +989,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
+ unlock_kernel();
exit:
DBGINFO(("%s wait_until_sent exit\n", info->device_name));
@@ -1097,6 +1103,7 @@ static int ioctl(struct tty_struct *tty, struct file *file,
struct serial_icounter_struct __user *p_cuser; /* user space */
unsigned long flags;
void __user *argp = (void __user *)arg;
+ int ret;
if (sanity_check(info, tty->name, "ioctl"))
return -ENODEV;
@@ -1108,37 +1115,54 @@ static int ioctl(struct tty_struct *tty, struct file *file,
return -EIO;
}
+ lock_kernel();
+
switch (cmd) {
case MGSL_IOCGPARAMS:
- return get_params(info, argp);
+ ret = get_params(info, argp);
+ break;
case MGSL_IOCSPARAMS:
- return set_params(info, argp);
+ ret = set_params(info, argp);
+ break;
case MGSL_IOCGTXIDLE:
- return get_txidle(info, argp);
+ ret = get_txidle(info, argp);
+ break;
case MGSL_IOCSTXIDLE:
- return set_txidle(info, (int)arg);
+ ret = set_txidle(info, (int)arg);
+ break;
case MGSL_IOCTXENABLE:
- return tx_enable(info, (int)arg);
+ ret = tx_enable(info, (int)arg);
+ break;
case MGSL_IOCRXENABLE:
- return rx_enable(info, (int)arg);
+ ret = rx_enable(info, (int)arg);
+ break;
case MGSL_IOCTXABORT:
- return tx_abort(info);
+ ret = tx_abort(info);
+ break;
case MGSL_IOCGSTATS:
- return get_stats(info, argp);
+ ret = get_stats(info, argp);
+ break;
case MGSL_IOCWAITEVENT:
- return wait_mgsl_event(info, argp);
+ ret = wait_mgsl_event(info, argp);
+ break;
case TIOCMIWAIT:
- return modem_input_wait(info,(int)arg);
+ ret = modem_input_wait(info,(int)arg);
+ break;
case MGSL_IOCGIF:
- return get_interface(info, argp);
+ ret = get_interface(info, argp);
+ break;
case MGSL_IOCSIF:
- return set_interface(info,(int)arg);
+ ret = set_interface(info,(int)arg);
+ break;
case MGSL_IOCSGPIO:
- return set_gpio(info, argp);
+ ret = set_gpio(info, argp);
+ break;
case MGSL_IOCGGPIO:
- return get_gpio(info, argp);
+ ret = get_gpio(info, argp);
+ break;
case MGSL_IOCWAITGPIO:
- return wait_gpio(info, argp);
+ ret = wait_gpio(info, argp);
+ break;
case TIOCGICOUNT:
spin_lock_irqsave(&info->lock,flags);
cnow = info->icount;
@@ -1155,12 +1179,14 @@ static int ioctl(struct tty_struct *tty, struct file *file,
put_user(cnow.parity, &p_cuser->parity) ||
put_user(cnow.brk, &p_cuser->brk) ||
put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ ret = 0;
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
- return 0;
+ unlock_kernel();
+ return ret;
}
/*
@@ -3324,7 +3350,7 @@ static int claim_resources(struct slgt_info *info)
else
info->reg_addr_requested = true;
- info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE);
+ info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE);
if (!info->reg_addr) {
DBGERR(("%s cant map device registers, addr=%08X\n",
info->device_name, info->phys_reg_addr));
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index e98c3e6f821..bec54866e0b 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -519,7 +519,7 @@ static void hangup(struct tty_struct *tty);
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void put_char(struct tty_struct *tty, unsigned char ch);
+static int put_char(struct tty_struct *tty, unsigned char ch);
static void send_xchar(struct tty_struct *tty, char ch);
static void wait_until_sent(struct tty_struct *tty, int timeout);
static int write_room(struct tty_struct *tty);
@@ -862,8 +862,7 @@ static void close(struct tty_struct *tty, struct file *filp)
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -1046,10 +1045,11 @@ cleanup:
/* Add a character to the transmit buffer.
*/
-static void put_char(struct tty_struct *tty, unsigned char ch)
+static int put_char(struct tty_struct *tty, unsigned char ch)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
unsigned long flags;
+ int ret = 0;
if ( debug_level >= DEBUG_LEVEL_INFO ) {
printk( "%s(%d):%s put_char(%d)\n",
@@ -1057,10 +1057,10 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
}
if (sanity_check(info, tty->name, "put_char"))
- return;
+ return 0;
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
@@ -1072,10 +1072,12 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
if (info->tx_put >= info->max_frame_size)
info->tx_put -= info->max_frame_size;
info->tx_count++;
+ ret = 1;
}
}
spin_unlock_irqrestore(&info->lock,flags);
+ return ret;
}
/* Send a high-priority XON/XOFF character
@@ -1119,6 +1121,8 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
if (sanity_check(info, tty->name, "wait_until_sent"))
return;
+ lock_kernel();
+
if (!(info->flags & ASYNC_INITIALIZED))
goto exit;
@@ -1161,6 +1165,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
}
exit:
+ unlock_kernel();
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s wait_until_sent() exit\n",
__FILE__,__LINE__, info->device_name );
@@ -1176,6 +1181,7 @@ static int write_room(struct tty_struct *tty)
if (sanity_check(info, tty->name, "write_room"))
return 0;
+ lock_kernel();
if (info->params.mode == MGSL_MODE_HDLC) {
ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
} else {
@@ -1183,6 +1189,7 @@ static int write_room(struct tty_struct *tty)
if (ret < 0)
ret = 0;
}
+ unlock_kernel();
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s write_room()=%d\n",
@@ -1303,7 +1310,7 @@ static void tx_release(struct tty_struct *tty)
*
* Return Value: 0 if success, otherwise error code
*/
-static int ioctl(struct tty_struct *tty, struct file *file,
+static int do_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
@@ -1393,6 +1400,16 @@ static int ioctl(struct tty_struct *tty, struct file *file,
return 0;
}
+static int ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ lock_kernel();
+ ret = do_ioctl(tty, file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
/*
* /proc fs routines....
*/
@@ -3626,7 +3643,8 @@ static int claim_resources(SLMP_INFO *info)
else
info->sca_statctrl_requested = true;
- info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE);
+ info->memory_base = ioremap_nocache(info->phys_memory_base,
+ SCA_MEM_SIZE);
if (!info->memory_base) {
printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -3634,7 +3652,7 @@ static int claim_resources(SLMP_INFO *info)
goto errout;
}
- info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE);
+ info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
@@ -3643,7 +3661,7 @@ static int claim_resources(SLMP_INFO *info)
}
info->lcr_base += info->lcr_offset;
- info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE);
+ info->sca_base = ioremap_nocache(info->phys_sca_base, PAGE_SIZE);
if (!info->sca_base) {
printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base );
@@ -3652,7 +3670,8 @@ static int claim_resources(SLMP_INFO *info)
}
info->sca_base += info->sca_offset;
- info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE);
+ info->statctrl_base = ioremap_nocache(info->phys_statctrl_base,
+ PAGE_SIZE);
if (!info->statctrl_base) {
printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 2fa6856706a..1d298c2cf93 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -91,7 +91,6 @@
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
-#include <linux/idr.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -137,9 +136,6 @@ EXPORT_SYMBOL(tty_mutex);
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
-extern int pty_limit; /* Config limit on Unix98 ptys */
-static DEFINE_IDR(allocated_ptys);
-static DEFINE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
@@ -152,8 +148,7 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
-int tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
@@ -1109,8 +1104,8 @@ restart:
a reference to the old ldisc. If we ended up flipping back
to the existing ldisc we have two references to it */
- if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc)
- tty->driver->set_ldisc(tty);
+ if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc)
+ tty->ops->set_ldisc(tty);
tty_ldisc_put(o_ldisc.num);
@@ -1182,9 +1177,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (*str == '\0')
str = NULL;
- if (tty_line >= 0 && tty_line <= p->num && p->poll_init &&
- !p->poll_init(p, tty_line, str)) {
-
+ if (tty_line >= 0 && tty_line <= p->num && p->ops &&
+ p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
res = p;
*line = tty_line;
break;
@@ -1205,26 +1199,37 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
* not in the foreground, send a SIGTTOU. If the signal is blocked or
* ignored, go ahead and perform the operation. (POSIX 7.2)
*
- * Locking: none
+ * Locking: ctrl_lock
*/
int tty_check_change(struct tty_struct *tty)
{
+ unsigned long flags;
+ int ret = 0;
+
if (current->signal->tty != tty)
return 0;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+
if (!tty->pgrp) {
printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
- return 0;
+ goto out;
}
if (task_pgrp(current) == tty->pgrp)
- return 0;
+ goto out;
if (is_ignored(SIGTTOU))
- return 0;
- if (is_current_pgrp_orphaned())
- return -EIO;
+ goto out;
+ if (is_current_pgrp_orphaned()) {
+ ret = -EIO;
+ goto out;
+ }
kill_pgrp(task_pgrp(current), SIGTTOU, 1);
set_thread_flag(TIF_SIGPENDING);
- return -ERESTARTSYS;
+ ret = -ERESTARTSYS;
+out:
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ return ret;
}
EXPORT_SYMBOL(tty_check_change);
@@ -1247,8 +1252,8 @@ static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
}
-static int hung_up_tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
@@ -1264,7 +1269,7 @@ static const struct file_operations tty_fops = {
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
@@ -1277,7 +1282,7 @@ static const struct file_operations ptmx_fops = {
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = ptmx_open,
.release = tty_release,
@@ -1290,7 +1295,7 @@ static const struct file_operations console_fops = {
.read = tty_read,
.write = redirected_tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
@@ -1302,7 +1307,7 @@ static const struct file_operations hung_up_tty_fops = {
.read = hung_up_tty_read,
.write = hung_up_tty_write,
.poll = hung_up_tty_poll,
- .ioctl = hung_up_tty_ioctl,
+ .unlocked_ioctl = hung_up_tty_ioctl,
.compat_ioctl = hung_up_tty_compat_ioctl,
.release = tty_release,
};
@@ -1404,6 +1409,7 @@ static void do_tty_hangup(struct work_struct *work)
struct task_struct *p;
struct tty_ldisc *ld;
int closecount = 0, n;
+ unsigned long flags;
if (!tty)
return;
@@ -1441,8 +1447,7 @@ static void do_tty_hangup(struct work_struct *work)
/* We may have no line discipline at this point */
if (ld->flush_buffer)
ld->flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->write_wakeup)
ld->write_wakeup(tty);
@@ -1480,19 +1485,24 @@ static void do_tty_hangup(struct work_struct *work)
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
put_pid(p->signal->tty_old_pgrp); /* A noop */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp)
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
spin_unlock_irq(&p->sighand->siglock);
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->flags = 0;
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
/*
* If one of the devices matches a console pointer, we
* cannot just call hangup() because that will cause
@@ -1500,11 +1510,11 @@ static void do_tty_hangup(struct work_struct *work)
* So we just call close() the right number of times.
*/
if (cons_filp) {
- if (tty->driver->close)
+ if (tty->ops->close)
for (n = 0; n < closecount; n++)
- tty->driver->close(tty, cons_filp);
- } else if (tty->driver->hangup)
- (tty->driver->hangup)(tty);
+ tty->ops->close(tty, cons_filp);
+ } else if (tty->ops->hangup)
+ (tty->ops->hangup)(tty);
/*
* We don't want to have driver/ldisc interactions beyond
* the ones we did here. The driver layer expects no
@@ -1626,16 +1636,17 @@ void disassociate_ctty(int on_exit)
struct tty_struct *tty;
struct pid *tty_pgrp = NULL;
- lock_kernel();
mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
tty_pgrp = get_pid(tty->pgrp);
mutex_unlock(&tty_mutex);
+ lock_kernel();
/* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
+ unlock_kernel();
} else if (on_exit) {
struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock);
@@ -1648,7 +1659,6 @@ void disassociate_ctty(int on_exit)
put_pid(old_pgrp);
}
mutex_unlock(&tty_mutex);
- unlock_kernel();
return;
}
if (tty_pgrp) {
@@ -1667,10 +1677,13 @@ void disassociate_ctty(int on_exit)
/* It is possible that do_tty_hangup has free'd this tty */
tty = get_current_tty();
if (tty) {
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
} else {
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1683,7 +1696,6 @@ void disassociate_ctty(int on_exit)
read_lock(&tasklist_lock);
session_clear_tty(task_session(current));
read_unlock(&tasklist_lock);
- unlock_kernel();
}
/**
@@ -1693,8 +1705,10 @@ void disassociate_ctty(int on_exit)
void no_tty(void)
{
struct task_struct *tsk = current;
+ lock_kernel();
if (tsk->signal->leader)
disassociate_ctty(0);
+ unlock_kernel();
proc_clear_tty(tsk);
}
@@ -1714,21 +1728,26 @@ void no_tty(void)
* but not always.
*
* Locking:
- * Broken. Relies on BKL which is unsafe here.
+ * Uses the tty control lock internally
*/
void stop_tty(struct tty_struct *tty)
{
- if (tty->stopped)
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (tty->stopped) {
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return;
+ }
tty->stopped = 1;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_START;
tty->ctrl_status |= TIOCPKT_STOP;
wake_up_interruptible(&tty->link->read_wait);
}
- if (tty->driver->stop)
- (tty->driver->stop)(tty);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->ops->stop)
+ (tty->ops->stop)(tty);
}
EXPORT_SYMBOL(stop_tty);
@@ -1743,21 +1762,26 @@ EXPORT_SYMBOL(stop_tty);
* driver start method is invoked and the line discipline woken.
*
* Locking:
- * Broken. Relies on BKL which is unsafe here.
+ * ctrl_lock
*/
void start_tty(struct tty_struct *tty)
{
- if (!tty->stopped || tty->flow_stopped)
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (!tty->stopped || tty->flow_stopped) {
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return;
+ }
tty->stopped = 0;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_STOP;
tty->ctrl_status |= TIOCPKT_START;
wake_up_interruptible(&tty->link->read_wait);
}
- if (tty->driver->start)
- (tty->driver->start)(tty);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->ops->start)
+ (tty->ops->start)(tty);
/* If we have a running line discipline it may need kicking */
tty_wakeup(tty);
}
@@ -1775,10 +1799,8 @@ EXPORT_SYMBOL(start_tty);
* for hung up devices before calling the line discipline method.
*
* Locking:
- * Locks the line discipline internally while needed
- * For historical reasons the line discipline read method is
- * invoked under the BKL. This will go away in time so do not rely on it
- * in new code. Multiple read calls may be outstanding in parallel.
+ * Locks the line discipline internally while needed. Multiple
+ * read calls may be outstanding in parallel.
*/
static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
@@ -1799,13 +1821,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
- lock_kernel();
if (ld->read)
i = (ld->read)(tty, file, buf, count);
else
i = -EIO;
tty_ldisc_deref(ld);
- unlock_kernel();
if (i > 0)
inode->i_atime = current_fs_time(inode->i_sb);
return i;
@@ -1893,9 +1913,7 @@ static inline ssize_t do_tty_write(
ret = -EFAULT;
if (copy_from_user(tty->write_buf, buf, size))
break;
- lock_kernel();
ret = write(tty, file, tty->write_buf, size);
- unlock_kernel();
if (ret <= 0)
break;
written += ret;
@@ -1948,10 +1966,13 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO;
- if (!tty || !tty->driver->write ||
+ if (!tty || !tty->ops->write ||
(test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
-
+ /* Short term debug to catch buggy drivers */
+ if (tty->ops->write_room == NULL)
+ printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
+ tty->driver->name);
ld = tty_ldisc_ref_wait(tty);
if (!ld->write)
ret = -EIO;
@@ -2098,6 +2119,7 @@ static int init_dev(struct tty_driver *driver, int idx,
goto fail_no_mem;
initialize_tty_struct(tty);
tty->driver = driver;
+ tty->ops = driver->ops;
tty->index = idx;
tty_line_name(driver, idx, tty->name);
@@ -2128,6 +2150,7 @@ static int init_dev(struct tty_driver *driver, int idx,
goto free_mem_out;
initialize_tty_struct(o_tty);
o_tty->driver = driver->other;
+ o_tty->ops = driver->ops;
o_tty->index = idx;
tty_line_name(driver->other, idx, o_tty->name);
@@ -2432,8 +2455,8 @@ static void release_dev(struct file *filp)
}
}
#endif
- if (tty->driver->close)
- tty->driver->close(tty, filp);
+ if (tty->ops->close)
+ tty->ops->close(tty, filp);
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
@@ -2612,15 +2635,9 @@ static void release_dev(struct file *filp)
*/
release_tty(tty, idx);
-#ifdef CONFIG_UNIX98_PTYS
/* Make this pty number available for reallocation */
- if (devpts) {
- mutex_lock(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, idx);
- mutex_unlock(&allocated_ptys_lock);
- }
-#endif
-
+ if (devpts)
+ devpts_kill_index(idx);
}
/**
@@ -2716,8 +2733,8 @@ got_driver:
printk(KERN_DEBUG "opening %s...", tty->name);
#endif
if (!retval) {
- if (tty->driver->open)
- retval = tty->driver->open(tty, filp);
+ if (tty->ops->open)
+ retval = tty->ops->open(tty, filp);
else
retval = -ENODEV;
}
@@ -2776,29 +2793,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
struct tty_struct *tty;
int retval;
int index;
- int idr_ret;
nonseekable_open(inode, filp);
/* find a device that is not in use. */
- mutex_lock(&allocated_ptys_lock);
- if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
- mutex_unlock(&allocated_ptys_lock);
- return -ENOMEM;
- }
- idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
- if (idr_ret < 0) {
- mutex_unlock(&allocated_ptys_lock);
- if (idr_ret == -EAGAIN)
- return -ENOMEM;
- return -EIO;
- }
- if (index >= pty_limit) {
- idr_remove(&allocated_ptys, index);
- mutex_unlock(&allocated_ptys_lock);
- return -EIO;
- }
- mutex_unlock(&allocated_ptys_lock);
+ index = devpts_new_index();
+ if (index < 0)
+ return index;
mutex_lock(&tty_mutex);
retval = init_dev(ptm_driver, index, &tty);
@@ -2811,21 +2812,19 @@ static int ptmx_open(struct inode *inode, struct file *filp)
filp->private_data = tty;
file_move(filp, &tty->tty_files);
- retval = -ENOMEM;
- if (devpts_pty_new(tty->link))
+ retval = devpts_pty_new(tty->link);
+ if (retval)
goto out1;
- check_tty_count(tty, "tty_open");
- retval = ptm_driver->open(tty, filp);
+ check_tty_count(tty, "ptmx_open");
+ retval = ptm_driver->ops->open(tty, filp);
if (!retval)
return 0;
out1:
release_dev(filp);
return retval;
out:
- mutex_lock(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, index);
- mutex_unlock(&allocated_ptys_lock);
+ devpts_kill_index(index);
return retval;
}
#endif
@@ -2882,6 +2881,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
static int tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty;
+ unsigned long flags;
int retval;
tty = (struct tty_struct *)filp->private_data;
@@ -2897,6 +2897,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp) {
pid = tty->pgrp;
type = PIDTYPE_PGID;
@@ -2904,6 +2905,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
pid = task_pid(current);
type = PIDTYPE_PID;
}
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0);
if (retval)
return retval;
@@ -2989,6 +2991,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize __user *arg)
{
struct winsize tmp_ws;
+ struct pid *pgrp, *rpgrp;
+ unsigned long flags;
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
@@ -3006,10 +3010,21 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
}
}
#endif
- if (tty->pgrp)
- kill_pgrp(tty->pgrp, SIGWINCH, 1);
- if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp)
- kill_pgrp(real_tty->pgrp, SIGWINCH, 1);
+ /* Get the PID values and reference them so we can
+ avoid holding the tty ctrl lock while sending signals */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ pgrp = get_pid(tty->pgrp);
+ rpgrp = get_pid(real_tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ if (pgrp)
+ kill_pgrp(pgrp, SIGWINCH, 1);
+ if (rpgrp != pgrp && rpgrp)
+ kill_pgrp(rpgrp, SIGWINCH, 1);
+
+ put_pid(pgrp);
+ put_pid(rpgrp);
+
tty->winsize = tmp_ws;
real_tty->winsize = tmp_ws;
done:
@@ -3070,10 +3085,13 @@ static int fionbio(struct file *file, int __user *p)
if (get_user(nonblock, p))
return -EFAULT;
+ /* file->f_flags is still BKL protected in the fs layer - vomit */
+ lock_kernel();
if (nonblock)
file->f_flags |= O_NONBLOCK;
else
file->f_flags &= ~O_NONBLOCK;
+ unlock_kernel();
return 0;
}
@@ -3131,6 +3149,27 @@ unlock:
}
/**
+ * tty_get_pgrp - return a ref counted pgrp pid
+ * @tty: tty to read
+ *
+ * Returns a refcounted instance of the pid struct for the process
+ * group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+ unsigned long flags;
+ struct pid *pgrp;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ pgrp = get_pid(tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
+/**
* tiocgpgrp - get process group
* @tty: tty passed by user
* @real_tty: tty side of the tty pased by the user if a pty else the tty
@@ -3144,13 +3183,18 @@ unlock:
static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
+ struct pid *pid;
+ int ret;
/*
* (tty == real_tty) is a cheap way of
* testing if the tty is NOT a master pty.
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- return put_user(pid_vnr(real_tty->pgrp), p);
+ pid = tty_get_pgrp(real_tty);
+ ret = put_user(pid_vnr(pid), p);
+ put_pid(pid);
+ return ret;
}
/**
@@ -3162,7 +3206,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
* Set the process group of the tty to the session passed. Only
* permitted where the tty session is our session.
*
- * Locking: None
+ * Locking: RCU, ctrl lock
*/
static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3170,6 +3214,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
struct pid *pgrp;
pid_t pgrp_nr;
int retval = tty_check_change(real_tty);
+ unsigned long flags;
if (retval == -EIO)
return -ENOTTY;
@@ -3192,8 +3237,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(real_tty->pgrp);
real_tty->pgrp = get_pid(pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
out_unlock:
rcu_read_unlock();
return retval;
@@ -3237,10 +3284,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
int ldisc;
+ int ret;
if (get_user(ldisc, p))
return -EFAULT;
- return tty_set_ldisc(tty, ldisc);
+
+ lock_kernel();
+ ret = tty_set_ldisc(tty, ldisc);
+ unlock_kernel();
+
+ return ret;
}
/**
@@ -3260,18 +3313,18 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
{
if (tty_write_lock(tty, 0) < 0)
return -EINTR;
- tty->driver->break_ctl(tty, -1);
+ tty->ops->break_ctl(tty, -1);
if (!signal_pending(current))
msleep_interruptible(duration);
- tty->driver->break_ctl(tty, 0);
+ tty->ops->break_ctl(tty, 0);
tty_write_unlock(tty);
- if (signal_pending(current))
+ if (!signal_pending(current))
return -EINTR;
return 0;
}
/**
- * tiocmget - get modem status
+ * tty_tiocmget - get modem status
* @tty: tty device
* @file: user file pointer
* @p: pointer to result
@@ -3286,8 +3339,8 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
{
int retval = -EINVAL;
- if (tty->driver->tiocmget) {
- retval = tty->driver->tiocmget(tty, file);
+ if (tty->ops->tiocmget) {
+ retval = tty->ops->tiocmget(tty, file);
if (retval >= 0)
retval = put_user(retval, p);
@@ -3296,7 +3349,7 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
}
/**
- * tiocmset - set modem status
+ * tty_tiocmset - set modem status
* @tty: tty device
* @file: user file pointer
* @cmd: command - clear bits, set bits or set all
@@ -3313,7 +3366,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
{
int retval = -EINVAL;
- if (tty->driver->tiocmset) {
+ if (tty->ops->tiocmset) {
unsigned int set, clear, val;
retval = get_user(val, p);
@@ -3337,7 +3390,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
- retval = tty->driver->tiocmset(tty, file, set, clear);
+ retval = tty->ops->tiocmset(tty, file, set, clear);
}
return retval;
}
@@ -3345,20 +3398,18 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
/*
* Split this up, as gcc can choke on it otherwise..
*/
-int tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct tty_struct *tty, *real_tty;
void __user *p = (void __user *)arg;
int retval;
struct tty_ldisc *ld;
+ struct inode *inode = file->f_dentry->d_inode;
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- /* CHECKME: is this safe as one end closes ? */
-
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -3367,21 +3418,28 @@ int tty_ioctl(struct inode *inode, struct file *file,
/*
* Break handling by driver
*/
- if (!tty->driver->break_ctl) {
+
+ retval = -EINVAL;
+
+ if (!tty->ops->break_ctl) {
switch (cmd) {
case TIOCSBRK:
case TIOCCBRK:
- if (tty->driver->ioctl)
- return tty->driver->ioctl(tty, file, cmd, arg);
- return -EINVAL;
+ if (tty->ops->ioctl)
+ retval = tty->ops->ioctl(tty, file, cmd, arg);
+ if (retval != -EINVAL && retval != -ENOIOCTLCMD)
+ printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
+ return retval;
/* These two ioctl's always return success; even if */
/* the driver doesn't support them. */
case TCSBRK:
case TCSBRKP:
- if (!tty->driver->ioctl)
+ if (!tty->ops->ioctl)
return 0;
- retval = tty->driver->ioctl(tty, file, cmd, arg);
+ retval = tty->ops->ioctl(tty, file, cmd, arg);
+ if (retval != -EINVAL && retval != -ENOIOCTLCMD)
+ printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
if (retval == -ENOIOCTLCMD)
retval = 0;
return retval;
@@ -3439,7 +3497,6 @@ int tty_ioctl(struct inode *inode, struct file *file,
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
- /* FIXME: check this is ok */
return put_user(tty->ldisc.num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
@@ -3451,11 +3508,13 @@ int tty_ioctl(struct inode *inode, struct file *file,
* Break handling
*/
case TIOCSBRK: /* Turn break on, unconditionally */
- tty->driver->break_ctl(tty, -1);
+ if (tty->ops->break_ctl)
+ tty->ops->break_ctl(tty, -1);
return 0;
case TIOCCBRK: /* Turn break off, unconditionally */
- tty->driver->break_ctl(tty, 0);
+ if (tty->ops->break_ctl)
+ tty->ops->break_ctl(tty, 0);
return 0;
case TCSBRK: /* SVID version: non-zero arg --> no break */
/* non-zero arg means wait for all output data
@@ -3484,8 +3543,8 @@ int tty_ioctl(struct inode *inode, struct file *file,
}
break;
}
- if (tty->driver->ioctl) {
- retval = (tty->driver->ioctl)(tty, file, cmd, arg);
+ if (tty->ops->ioctl) {
+ retval = (tty->ops->ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@@ -3512,8 +3571,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- if (tty->driver->compat_ioctl) {
- retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+ if (tty->ops->compat_ioctl) {
+ retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@@ -3563,8 +3622,7 @@ void __do_SAK(struct tty_struct *tty)
tty_ldisc_flush(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
read_lock(&tasklist_lock);
/* Kill the entire session */
@@ -3770,19 +3828,32 @@ static void initialize_tty_struct(struct tty_struct *tty)
mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->read_lock);
+ spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
}
-/*
- * The default put_char routine if the driver did not define one.
+/**
+ * tty_put_char - write one character to a tty
+ * @tty: tty
+ * @ch: character
+ *
+ * Write one byte to the tty using the provided put_char method
+ * if present. Returns the number of characters successfully output.
+ *
+ * Note: the specific put_char operation in the driver layer may go
+ * away soon. Don't call it directly, use this method
*/
-static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
+int tty_put_char(struct tty_struct *tty, unsigned char ch)
{
- tty->driver->write(tty, &ch, 1);
+ if (tty->ops->put_char)
+ return tty->ops->put_char(tty, ch);
+ return tty->ops->write(tty, &ch, 1);
}
+EXPORT_SYMBOL_GPL(tty_put_char);
+
static struct class *tty_class;
/**
@@ -3865,37 +3936,8 @@ void put_tty_driver(struct tty_driver *driver)
void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op)
{
- driver->open = op->open;
- driver->close = op->close;
- driver->write = op->write;
- driver->put_char = op->put_char;
- driver->flush_chars = op->flush_chars;
- driver->write_room = op->write_room;
- driver->chars_in_buffer = op->chars_in_buffer;
- driver->ioctl = op->ioctl;
- driver->compat_ioctl = op->compat_ioctl;
- driver->set_termios = op->set_termios;
- driver->throttle = op->throttle;
- driver->unthrottle = op->unthrottle;
- driver->stop = op->stop;
- driver->start = op->start;
- driver->hangup = op->hangup;
- driver->break_ctl = op->break_ctl;
- driver->flush_buffer = op->flush_buffer;
- driver->set_ldisc = op->set_ldisc;
- driver->wait_until_sent = op->wait_until_sent;
- driver->send_xchar = op->send_xchar;
- driver->read_proc = op->read_proc;
- driver->write_proc = op->write_proc;
- driver->tiocmget = op->tiocmget;
- driver->tiocmset = op->tiocmset;
-#ifdef CONFIG_CONSOLE_POLL
- driver->poll_init = op->poll_init;
- driver->poll_get_char = op->poll_get_char;
- driver->poll_put_char = op->poll_put_char;
-#endif
-}
-
+ driver->ops = op;
+};
EXPORT_SYMBOL(alloc_tty_driver);
EXPORT_SYMBOL(put_tty_driver);
@@ -3958,9 +4000,6 @@ int tty_register_driver(struct tty_driver *driver)
return error;
}
- if (!driver->put_char)
- driver->put_char = tty_default_put_char;
-
mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
mutex_unlock(&tty_mutex);
@@ -4036,14 +4075,19 @@ void proc_clear_tty(struct task_struct *p)
}
EXPORT_SYMBOL(proc_clear_tty);
+/* Called under the sighand lock */
+
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
if (tty) {
- /* We should not have a session or pgrp to here but.... */
+ unsigned long flags;
+ /* We should not have a session or pgrp to put here but.... */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
- tty->session = get_pid(task_session(tsk));
tty->pgrp = get_pid(task_pgrp(tsk));
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ tty->session = get_pid(task_session(tsk));
}
put_pid(tsk->signal->tty_old_pgrp);
tsk->signal->tty = tty;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index f95a80b2265..b1a757a5ee2 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -39,6 +40,50 @@
#define TERMIOS_OLD 8
+int tty_chars_in_buffer(struct tty_struct *tty)
+{
+ if (tty->ops->chars_in_buffer)
+ return tty->ops->chars_in_buffer(tty);
+ else
+ return 0;
+}
+
+EXPORT_SYMBOL(tty_chars_in_buffer);
+
+int tty_write_room(struct tty_struct *tty)
+{
+ if (tty->ops->write_room)
+ return tty->ops->write_room(tty);
+ return 2048;
+}
+
+EXPORT_SYMBOL(tty_write_room);
+
+void tty_driver_flush_buffer(struct tty_struct *tty)
+{
+ if (tty->ops->flush_buffer)
+ tty->ops->flush_buffer(tty);
+}
+
+EXPORT_SYMBOL(tty_driver_flush_buffer);
+
+void tty_throttle(struct tty_struct *tty)
+{
+ /* check TTY_THROTTLED first so it indicates our state */
+ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->ops->throttle)
+ tty->ops->throttle(tty);
+}
+EXPORT_SYMBOL(tty_throttle);
+
+void tty_unthrottle(struct tty_struct *tty)
+{
+ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->ops->unthrottle)
+ tty->ops->unthrottle(tty);
+}
+EXPORT_SYMBOL(tty_unthrottle);
+
/**
* tty_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for
@@ -57,15 +102,13 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
#endif
- if (!tty->driver->chars_in_buffer)
- return;
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
if (wait_event_interruptible_timeout(tty->write_wait,
- !tty->driver->chars_in_buffer(tty), timeout) < 0)
- return;
- if (tty->driver->wait_until_sent)
- tty->driver->wait_until_sent(tty, timeout);
+ !tty_chars_in_buffer(tty), timeout) >= 0) {
+ if (tty->ops->wait_until_sent)
+ tty->ops->wait_until_sent(tty, timeout);
+ }
}
EXPORT_SYMBOL(tty_wait_until_sent);
@@ -393,8 +436,9 @@ EXPORT_SYMBOL(tty_termios_hw_change);
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
int canon_change;
- struct ktermios old_termios = *tty->termios;
+ struct ktermios old_termios;
struct tty_ldisc *ld;
+ unsigned long flags;
/*
* Perform the actual termios internal changes under lock.
@@ -404,7 +448,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
mutex_lock(&tty->termios_mutex);
-
+ old_termios = *tty->termios;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@ -429,17 +473,19 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if (old_flow != new_flow) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
wake_up_interruptible(&tty->link->read_wait);
}
}
- if (tty->driver->set_termios)
- (*tty->driver->set_termios)(tty, &old_termios);
+ if (tty->ops->set_termios)
+ (*tty->ops->set_termios)(tty, &old_termios);
else
tty_termios_copy_hw(tty->termios, &old_termios);
@@ -474,7 +520,9 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
if (retval)
return retval;
+ mutex_lock(&tty->termios_mutex);
memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+ mutex_unlock(&tty->termios_mutex);
if (opt & TERMIOS_TERMIO) {
if (user_termio_to_kernel_termios(&tmp_termios,
@@ -660,12 +708,14 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
{
struct tchars tmp;
+ mutex_lock(&tty->termios_mutex);
tmp.t_intrc = tty->termios->c_cc[VINTR];
tmp.t_quitc = tty->termios->c_cc[VQUIT];
tmp.t_startc = tty->termios->c_cc[VSTART];
tmp.t_stopc = tty->termios->c_cc[VSTOP];
tmp.t_eofc = tty->termios->c_cc[VEOF];
tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -675,12 +725,14 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cc[VINTR] = tmp.t_intrc;
tty->termios->c_cc[VQUIT] = tmp.t_quitc;
tty->termios->c_cc[VSTART] = tmp.t_startc;
tty->termios->c_cc[VSTOP] = tmp.t_stopc;
tty->termios->c_cc[VEOF] = tmp.t_eofc;
tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
#endif
@@ -690,6 +742,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
{
struct ltchars tmp;
+ mutex_lock(&tty->termios_mutex);
tmp.t_suspc = tty->termios->c_cc[VSUSP];
/* what is dsuspc anyway? */
tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
@@ -698,6 +751,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
tmp.t_flushc = tty->termios->c_cc[VEOL2];
tmp.t_werasc = tty->termios->c_cc[VWERASE];
tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -708,6 +762,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cc[VSUSP] = tmp.t_suspc;
/* what is dsuspc anyway? */
tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
@@ -716,6 +771,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
tty->termios->c_cc[VEOL2] = tmp.t_flushc;
tty->termios->c_cc[VWERASE] = tmp.t_werasc;
tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
#endif
@@ -732,8 +788,8 @@ static int send_prio_char(struct tty_struct *tty, char ch)
{
int was_stopped = tty->stopped;
- if (tty->driver->send_xchar) {
- tty->driver->send_xchar(tty, ch);
+ if (tty->ops->send_xchar) {
+ tty->ops->send_xchar(tty, ch);
return 0;
}
@@ -742,7 +798,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
if (was_stopped)
start_tty(tty);
- tty->driver->write(tty, &ch, 1);
+ tty->ops->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
tty_write_unlock(tty);
@@ -750,6 +806,33 @@ static int send_prio_char(struct tty_struct *tty, char ch)
}
/**
+ * tty_change_softcar - carrier change ioctl helper
+ * @tty: tty to update
+ * @arg: enable/disable CLOCAL
+ *
+ * Perform a change to the CLOCAL state and call into the driver
+ * layer to make it visible. All done with the termios mutex
+ */
+
+static int tty_change_softcar(struct tty_struct *tty, int arg)
+{
+ int ret = 0;
+ int bit = arg ? CLOCAL : 0;
+ struct ktermios old;
+
+ mutex_lock(&tty->termios_mutex);
+ old = *tty->termios;
+ tty->termios->c_cflag &= ~CLOCAL;
+ tty->termios->c_cflag |= bit;
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old);
+ if ((tty->termios->c_cflag & CLOCAL) != bit)
+ ret = -EINVAL;
+ mutex_unlock(&tty->termios_mutex);
+ return ret;
+}
+
+/**
* tty_mode_ioctl - mode related ioctls
* @tty: tty for the ioctl
* @file: file pointer for the tty
@@ -859,12 +942,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
- mutex_lock(&tty->termios_mutex);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- mutex_unlock(&tty->termios_mutex);
- return 0;
+ return tty_change_softcar(tty, arg);
default:
return -ENOIOCTLCMD;
}
@@ -889,8 +967,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
ld->flush_buffer(tty);
/* fall through */
case TCOFLUSH:
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
break;
default:
tty_ldisc_deref(ld);
@@ -905,6 +982,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct tty_struct *real_tty;
+ unsigned long flags;
int retval;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -946,9 +1024,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
case TCFLSH:
return tty_perform_flush(tty, arg);
case TIOCOUTQ:
- return put_user(tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0,
- (int __user *) arg);
+ return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
retval = tty->read_cnt;
if (L_ICANON(tty))
@@ -963,6 +1039,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return -ENOTTY;
if (get_user(pktmode, (int __user *) arg))
return -EFAULT;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (pktmode) {
if (!tty->packet) {
tty->packet = 1;
@@ -970,6 +1047,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
}
} else
tty->packet = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return 0;
}
default:
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 8de6b95aeb8..3d3e1c2b310 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -628,13 +628,13 @@ static int viotty_write(struct tty_struct *tty, const unsigned char *buf,
/*
* TTY put_char method
*/
-static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
+static int viotty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct port_info *pi;
pi = get_port_data(tty);
if (pi == NULL)
- return;
+ return 0;
/* This will append '\r' as well if the char is '\n' */
if (viochar_is_console(pi))
@@ -642,6 +642,7 @@ static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
if (viopath_isactive(pi->lp))
internal_write(pi, &ch, 1);
+ return 1;
}
/*
@@ -704,8 +705,11 @@ static int viotty_ioctl(struct tty_struct *tty, struct file *file,
case KDSKBLED:
return 0;
}
-
- return n_tty_ioctl(tty, file, cmd, arg);
+ /* FIXME: WTF is this being called for ??? */
+ lock_kernel();
+ ret = n_tty_ioctl(tty, file, cmd, arg);
+ unlock_kernel();
+ return ret;
}
/*
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 1c266047713..e458b08139a 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -909,15 +909,21 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
if (vc->vc_tty) {
struct winsize ws, *cws = &vc->vc_tty->winsize;
+ unsigned long flags;
memset(&ws, 0, sizeof(ws));
ws.ws_row = vc->vc_rows;
ws.ws_col = vc->vc_cols;
ws.ws_ypixel = vc->vc_scan_lines;
+
+ mutex_lock(&vc->vc_tty->termios_mutex);
+ spin_lock_irqsave(&vc->vc_tty->ctrl_lock, flags);
if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
vc->vc_tty->pgrp)
kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
+ spin_unlock_irqrestore(&vc->vc_tty->ctrl_lock, flags);
*cws = ws;
+ mutex_unlock(&vc->vc_tty->termios_mutex);
}
if (CON_IS_VISIBLE(vc))
@@ -2541,6 +2547,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
if (get_user(type, p))
return -EFAULT;
ret = 0;
+
+ lock_kernel();
+
switch (type)
{
case TIOCL_SETSEL:
@@ -2560,7 +2569,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
ret = sel_loadlut(p);
break;
case TIOCL_GETSHIFTSTATE:
-
+
/*
* Make it possible to react to Shift+Mousebutton.
* Note that 'shift_state' is an undocumented
@@ -2615,6 +2624,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
ret = -EINVAL;
break;
}
+ unlock_kernel();
return ret;
}
@@ -2632,11 +2642,11 @@ static int con_write(struct tty_struct *tty, const unsigned char *buf, int count
return retval;
}
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
+static int con_put_char(struct tty_struct *tty, unsigned char ch)
{
if (in_interrupt())
- return; /* n_r3964 calls put_char() from interrupt context */
- do_con_write(tty, &ch, 1);
+ return 0; /* n_r3964 calls put_char() from interrupt context */
+ return do_con_write(tty, &ch, 1);
}
static int con_write_room(struct tty_struct *tty)
@@ -3829,7 +3839,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
goto out;
c = (font.width+7)/8 * 32 * font.charcount;
-
+
if (op->data && font.charcount > op->charcount)
rc = -ENOSPC;
if (!(op->flags & KD_FONT_FLAG_OLD)) {
@@ -3994,6 +4004,7 @@ u16 screen_glyph(struct vc_data *vc, int offset)
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);
/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index e6f89e8b925..3211afd9d57 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -373,11 +373,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned char ucval;
void __user *up = (void __user *)arg;
int i, perm;
-
+ int ret = 0;
+
console = vc->vc_num;
- if (!vc_cons_allocated(console)) /* impossible? */
- return -ENOIOCTLCMD;
+ lock_kernel();
+
+ if (!vc_cons_allocated(console)) { /* impossible? */
+ ret = -ENOIOCTLCMD;
+ goto out;
+ }
+
/*
* To have permissions to do most of the vt ioctls, we either have
@@ -391,15 +397,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd) {
case KIOCSOUND:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg)
arg = CLOCK_TICK_RATE / arg;
kd_mksound(arg, 0);
- return 0;
+ break;
case KDMKTONE:
if (!perm)
- return -EPERM;
+ goto eperm;
{
unsigned int ticks, count;
@@ -412,7 +418,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (count)
count = CLOCK_TICK_RATE / count;
kd_mksound(count, ticks);
- return 0;
+ break;
}
case KDGKBTYPE:
@@ -435,14 +441,18 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* KDADDIO and KDDELIO may be able to add ports beyond what
* we reject here, but to be safe...
*/
- if (arg < GPFIRST || arg > GPLAST)
- return -EINVAL;
- return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+ if (arg < GPFIRST || arg > GPLAST) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+ break;
case KDENABIO:
case KDDISABIO:
- return sys_ioperm(GPFIRST, GPNUM,
+ ret = sys_ioperm(GPFIRST, GPNUM,
(cmd == KDENABIO)) ? -ENXIO : 0;
+ break;
#endif
/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
@@ -450,19 +460,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDKBDREP:
{
struct kbd_repeat kbrep;
- int err;
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
- if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat)))
- return -EFAULT;
- err = kbd_rate(&kbrep);
- if (err)
- return err;
+ if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = kbd_rate(&kbrep);
+ if (ret)
+ break;
if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
case KDSETMODE:
@@ -475,7 +486,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* need to restore their engine state. --BenH
*/
if (!perm)
- return -EPERM;
+ goto eperm;
switch (arg) {
case KD_GRAPHICS:
break;
@@ -485,13 +496,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KD_TEXT:
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (vc->vc_mode == (unsigned char) arg)
- return 0;
+ break;
vc->vc_mode = (unsigned char) arg;
if (console != fg_console)
- return 0;
+ break;
/*
* explicitly blank/unblank the screen if switching modes
*/
@@ -501,7 +513,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
else
do_blank_screen(1);
release_console_sem();
- return 0;
+ break;
case KDGETMODE:
ucval = vc->vc_mode;
@@ -513,11 +525,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* these work like a combination of mmap and KDENABIO.
* this could be easily finished.
*/
- return -EINVAL;
+ ret = -EINVAL;
+ break;
case KDSKBMODE:
if (!perm)
- return -EPERM;
+ goto eperm;
switch(arg) {
case K_RAW:
kbd->kbdmode = VC_RAW;
@@ -534,10 +547,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
compute_shiftstate();
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
tty_ldisc_flush(tty);
- return 0;
+ break;
case KDGKBMODE:
ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
@@ -557,28 +571,32 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
set_vc_kbd_mode(kbd, VC_META);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ break;
case KDGKBMETA:
ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
setint:
- return put_user(ucval, (int __user *)arg);
+ ret = put_user(ucval, (int __user *)arg);
+ break;
case KDGETKEYCODE:
case KDSETKEYCODE:
if(!capable(CAP_SYS_TTY_CONFIG))
- perm=0;
- return do_kbkeycode_ioctl(cmd, up, perm);
+ perm = 0;
+ ret = do_kbkeycode_ioctl(cmd, up, perm);
+ break;
case KDGKBENT:
case KDSKBENT:
- return do_kdsk_ioctl(cmd, up, perm, kbd);
+ ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+ break;
case KDGKBSENT:
case KDSKBSENT:
- return do_kdgkb_ioctl(cmd, up, perm);
+ ret = do_kdgkb_ioctl(cmd, up, perm);
+ break;
case KDGKBDIACR:
{
@@ -586,26 +604,31 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct kbdiacr diacr;
int i;
- if (put_user(accent_table_size, &a->kb_cnt))
- return -EFAULT;
+ if (put_user(accent_table_size, &a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
for (i = 0; i < accent_table_size; i++) {
diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
diacr.base = conv_uni_to_8bit(accent_table[i].base);
diacr.result = conv_uni_to_8bit(accent_table[i].result);
- if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
- return -EFAULT;
+ if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
+ ret = -EFAULT;
+ break;
+ }
}
- return 0;
+ break;
}
case KDGKBDIACRUC:
{
struct kbdiacrsuc __user *a = up;
if (put_user(accent_table_size, &a->kb_cnt))
- return -EFAULT;
- if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ else if (copy_to_user(a->kbdiacruc, accent_table,
+ accent_table_size*sizeof(struct kbdiacruc)))
+ ret = -EFAULT;
+ break;
}
case KDSKBDIACR:
@@ -616,20 +639,26 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
int i;
if (!perm)
- return -EPERM;
- if (get_user(ct,&a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ goto eperm;
+ if (get_user(ct,&a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (ct >= MAX_DIACR) {
+ ret = -EINVAL;
+ break;
+ }
accent_table_size = ct;
for (i = 0; i < ct; i++) {
- if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
- return -EFAULT;
+ if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
+ ret = -EFAULT;
+ break;
+ }
accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
accent_table[i].base = conv_8bit_to_uni(diacr.base);
accent_table[i].result = conv_8bit_to_uni(diacr.result);
}
- return 0;
+ break;
}
case KDSKBDIACRUC:
@@ -638,15 +667,19 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int ct;
if (!perm)
- return -EPERM;
- if (get_user(ct,&a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ goto eperm;
+ if (get_user(ct,&a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (ct >= MAX_DIACR) {
+ ret = -EINVAL;
+ break;
+ }
accent_table_size = ct;
if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
/* the ioctls below read/set the flags usually shown in the leds */
@@ -657,26 +690,29 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSKBLED:
if (!perm)
- return -EPERM;
- if (arg & ~0x77)
- return -EINVAL;
+ goto eperm;
+ if (arg & ~0x77) {
+ ret = -EINVAL;
+ break;
+ }
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
- return 0;
+ break;
/* the ioctls below only set the lights, not the functions */
/* for those, see KDGKBLED and KDSKBLED above */
case KDGETLED:
ucval = getledstate();
setchar:
- return put_user(ucval, (char __user *)arg);
+ ret = put_user(ucval, (char __user *)arg);
+ break;
case KDSETLED:
if (!perm)
- return -EPERM;
+ goto eperm;
setledstate(kbd, arg);
- return 0;
+ break;
/*
* A process can indicate its willingness to accept signals
@@ -688,16 +724,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSIGACCEPT:
{
if (!perm || !capable(CAP_KILL))
- return -EPERM;
+ goto eperm;
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
- return -EINVAL;
-
- spin_lock_irq(&vt_spawn_con.lock);
- put_pid(vt_spawn_con.pid);
- vt_spawn_con.pid = get_pid(task_pid(current));
- vt_spawn_con.sig = arg;
- spin_unlock_irq(&vt_spawn_con.lock);
- return 0;
+ ret = -EINVAL;
+ else {
+ spin_lock_irq(&vt_spawn_con.lock);
+ put_pid(vt_spawn_con.pid);
+ vt_spawn_con.pid = get_pid(task_pid(current));
+ vt_spawn_con.sig = arg;
+ spin_unlock_irq(&vt_spawn_con.lock);
+ }
+ break;
}
case VT_SETMODE:
@@ -705,11 +742,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct vt_mode tmp;
if (!perm)
- return -EPERM;
- if (copy_from_user(&tmp, up, sizeof(struct vt_mode)))
- return -EFAULT;
- if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
- return -EINVAL;
+ goto eperm;
+ if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+ ret = -EINVAL;
+ goto out;
+ }
acquire_console_sem();
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
@@ -719,7 +760,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
release_console_sem();
- return 0;
+ break;
}
case VT_GETMODE:
@@ -732,7 +773,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
release_console_sem();
rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
- return rc ? -EFAULT : 0;
+ if (rc)
+ ret = -EFAULT;
+ break;
}
/*
@@ -746,12 +789,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned short state, mask;
if (put_user(fg_console + 1, &vtstat->v_active))
- return -EFAULT;
- state = 1; /* /dev/tty0 is always open */
- for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
- if (VT_IS_IN_USE(i))
- state |= mask;
- return put_user(state, &vtstat->v_state);
+ ret = -EFAULT;
+ else {
+ state = 1; /* /dev/tty0 is always open */
+ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+ ++i, mask <<= 1)
+ if (VT_IS_IN_USE(i))
+ state |= mask;
+ ret = put_user(state, &vtstat->v_state);
+ }
+ break;
}
/*
@@ -771,27 +818,31 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
case VT_ACTIVATE:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- return -ENXIO;
- arg--;
- acquire_console_sem();
- i = vc_allocate(arg);
- release_console_sem();
- if (i)
- return i;
- set_console(arg);
- return 0;
+ ret = -ENXIO;
+ else {
+ arg--;
+ acquire_console_sem();
+ ret = vc_allocate(arg);
+ release_console_sem();
+ if (ret)
+ break;
+ set_console(arg);
+ }
+ break;
/*
* wait until the specified VT has been activated
*/
case VT_WAITACTIVE:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- return -ENXIO;
- return vt_waitactive(arg-1);
+ ret = -ENXIO;
+ else
+ ret = vt_waitactive(arg - 1);
+ break;
/*
* If a vt is under process control, the kernel will not switch to it
@@ -805,10 +856,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
case VT_RELDISP:
if (!perm)
- return -EPERM;
- if (vc->vt_mode.mode != VT_PROCESS)
- return -EINVAL;
+ goto eperm;
+ if (vc->vt_mode.mode != VT_PROCESS) {
+ ret = -EINVAL;
+ break;
+ }
/*
* Switching-from response
*/
@@ -829,10 +882,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
int newvt;
newvt = vc->vt_newvt;
vc->vt_newvt = -1;
- i = vc_allocate(newvt);
- if (i) {
+ ret = vc_allocate(newvt);
+ if (ret) {
release_console_sem();
- return i;
+ break;
}
/*
* When we actually do the console switch,
@@ -841,31 +894,27 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
complete_change_console(vc_cons[newvt].d);
}
- }
-
- /*
- * Switched-to response
- */
- else
- {
+ } else {
+ /*
+ * Switched-to response
+ */
/*
* If it's just an ACK, ignore it
*/
- if (arg != VT_ACKACQ) {
- release_console_sem();
- return -EINVAL;
- }
+ if (arg != VT_ACKACQ)
+ ret = -EINVAL;
}
release_console_sem();
-
- return 0;
+ break;
/*
* Disallocate memory associated to VT (but leave VT1)
*/
case VT_DISALLOCATE:
- if (arg > MAX_NR_CONSOLES)
- return -ENXIO;
+ if (arg > MAX_NR_CONSOLES) {
+ ret = -ENXIO;
+ break;
+ }
if (arg == 0) {
/* deallocate all unused consoles, but leave 0 */
acquire_console_sem();
@@ -877,14 +926,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
/* deallocate a single console, if possible */
arg--;
if (VT_BUSY(arg))
- return -EBUSY;
- if (arg) { /* leave 0 */
+ ret = -EBUSY;
+ else if (arg) { /* leave 0 */
acquire_console_sem();
vc_deallocate(arg);
release_console_sem();
}
}
- return 0;
+ break;
case VT_RESIZE:
{
@@ -893,21 +942,21 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ushort ll,cc;
if (!perm)
- return -EPERM;
+ goto eperm;
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
- return -EFAULT;
-
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- vc = vc_cons[i].d;
+ ret = -EFAULT;
+ else {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ vc = vc_cons[i].d;
- if (vc) {
- vc->vc_resize_user = 1;
- vc_lock_resize(vc_cons[i].d, cc, ll);
+ if (vc) {
+ vc->vc_resize_user = 1;
+ vc_lock_resize(vc_cons[i].d, cc, ll);
+ }
}
}
-
- return 0;
+ break;
}
case VT_RESIZEX:
@@ -915,10 +964,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct vt_consize __user *vtconsize = up;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
- return -EPERM;
+ goto eperm;
if (!access_ok(VERIFY_READ, vtconsize,
- sizeof(struct vt_consize)))
- return -EFAULT;
+ sizeof(struct vt_consize))) {
+ ret = -EFAULT;
+ break;
+ }
+ /* FIXME: Should check the copies properly */
__get_user(ll, &vtconsize->v_rows);
__get_user(cc, &vtconsize->v_cols);
__get_user(vlin, &vtconsize->v_vlin);
@@ -928,21 +980,28 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vlin = vlin ? vlin : vc->vc_scan_lines;
if (clin) {
if (ll) {
- if (ll != vlin/clin)
- return -EINVAL; /* Parameters don't add up */
+ if (ll != vlin/clin) {
+ /* Parameters don't add up */
+ ret = -EINVAL;
+ break;
+ }
} else
ll = vlin/clin;
}
if (vcol && ccol) {
if (cc) {
- if (cc != vcol/ccol)
- return -EINVAL;
+ if (cc != vcol/ccol) {
+ ret = -EINVAL;
+ break;
+ }
} else
cc = vcol/ccol;
}
- if (clin > 32)
- return -EINVAL;
+ if (clin > 32) {
+ ret = -EINVAL;
+ break;
+ }
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons[i].d)
@@ -956,19 +1015,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vc_resize(vc_cons[i].d, cc, ll);
release_console_sem();
}
- return 0;
+ break;
}
case PIO_FONT: {
if (!perm)
- return -EPERM;
+ goto eperm;
op.op = KD_FONT_OP_SET;
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
op.width = 8;
op.height = 0;
op.charcount = 256;
op.data = up;
- return con_font_op(vc_cons[fg_console].d, &op);
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ break;
}
case GIO_FONT: {
@@ -978,100 +1038,124 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
op.height = 32;
op.charcount = 256;
op.data = up;
- return con_font_op(vc_cons[fg_console].d, &op);
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ break;
}
case PIO_CMAP:
if (!perm)
- return -EPERM;
- return con_set_cmap(up);
+ ret = -EPERM;
+ else
+ ret = con_set_cmap(up);
+ break;
case GIO_CMAP:
- return con_get_cmap(up);
+ ret = con_get_cmap(up);
+ break;
case PIO_FONTX:
case GIO_FONTX:
- return do_fontx_ioctl(cmd, up, perm, &op);
+ ret = do_fontx_ioctl(cmd, up, perm, &op);
+ break;
case PIO_FONTRESET:
{
if (!perm)
- return -EPERM;
+ goto eperm;
#ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
font is not saved. */
- return -ENOSYS;
+ ret = -ENOSYS;
+ break;
#else
{
op.op = KD_FONT_OP_SET_DEFAULT;
op.data = NULL;
- i = con_font_op(vc_cons[fg_console].d, &op);
- if (i)
- return i;
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ if (ret)
+ break;
con_set_default_unimap(vc_cons[fg_console].d);
- return 0;
+ break;
}
#endif
}
case KDFONTOP: {
- if (copy_from_user(&op, up, sizeof(op)))
- return -EFAULT;
+ if (copy_from_user(&op, up, sizeof(op))) {
+ ret = -EFAULT;
+ break;
+ }
if (!perm && op.op != KD_FONT_OP_GET)
- return -EPERM;
- i = con_font_op(vc, &op);
- if (i) return i;
+ goto eperm;
+ ret = con_font_op(vc, &op);
+ if (ret)
+ break;
if (copy_to_user(up, &op, sizeof(op)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
case PIO_SCRNMAP:
if (!perm)
- return -EPERM;
- return con_set_trans_old(up);
+ ret = -EPERM;
+ else
+ ret = con_set_trans_old(up);
+ break;
case GIO_SCRNMAP:
- return con_get_trans_old(up);
+ ret = con_get_trans_old(up);
+ break;
case PIO_UNISCRNMAP:
if (!perm)
- return -EPERM;
- return con_set_trans_new(up);
+ ret = -EPERM;
+ else
+ ret = con_set_trans_new(up);
+ break;
case GIO_UNISCRNMAP:
- return con_get_trans_new(up);
+ ret = con_get_trans_new(up);
+ break;
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
- return -EPERM;
- i = copy_from_user(&ui, up, sizeof(struct unimapinit));
- if (i) return -EFAULT;
- con_clear_unimap(vc, &ui);
- return 0;
+ goto eperm;
+ ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
+ if (!ret)
+ con_clear_unimap(vc, &ui);
+ break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
- return do_unimap_ioctl(cmd, up, perm, vc);
+ ret = do_unimap_ioctl(cmd, up, perm, vc);
+ break;
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
vt_dont_switch = 1;
- return 0;
+ break;
case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
vt_dont_switch = 0;
- return 0;
+ break;
case VT_GETHIFONTMASK:
- return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg);
+ ret = put_user(vc->vc_hi_font_mask,
+ (unsigned short __user *)arg);
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
+out:
+ unlock_kernel();
+ return ret;
+eperm:
+ ret = -EPERM;
+ goto out;
}
/*
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 24c62b848bf..7f138c6195f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -382,7 +382,7 @@ fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
pr_debug("%s: gpio-%d status %d\n",
- __FUNCTION__, gpio, status);
+ __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_direction_input);
@@ -420,7 +420,7 @@ fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
pr_debug("%s: gpio-%d status %d\n",
- __FUNCTION__, gpio, status);
+ __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_direction_output);
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index ed71a8bc70d..5c8b6e0ff47 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -224,7 +224,7 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
if (in_data & 0xF000) {
printk(KERN_DEBUG
"%s : Doesn't look like an ads7828 device\n",
- __FUNCTION__);
+ __func__);
goto exit_free;
}
}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index e1a3a79ab3f..7ff71ba7b7c 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -46,7 +46,7 @@ struct serport {
static int serport_serio_write(struct serio *serio, unsigned char data)
{
struct serport *serport = serio->port_data;
- return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
+ return -(serport->tty->ops->write(serport->tty, &data, 1) != 1);
}
static int serport_serio_open(struct serio *serio)
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 24c6b7ca62b..6ca0bb949ad 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1111,11 +1111,12 @@ static int capinc_tty_write(struct tty_struct * tty,
return count;
}
-static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
unsigned long flags;
+ int ret = 1;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
@@ -1125,7 +1126,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
#endif
- return;
+ return 0;
}
spin_lock_irqsave(&workaround_lock, flags);
@@ -1134,7 +1135,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
if (skb_tailroom(skb) > 0) {
*(skb_put(skb, 1)) = ch;
spin_unlock_irqrestore(&workaround_lock, flags);
- return;
+ return 1;
}
mp->ttyskb = NULL;
skb_queue_tail(&mp->outqueue, skb);
@@ -1148,8 +1149,10 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
mp->ttyskb = skb;
} else {
printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+ ret = 0;
}
spin_unlock_irqrestore(&workaround_lock, flags);
+ return ret;
}
static void capinc_tty_flush_chars(struct tty_struct *tty)
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index fceeb1d5768..45d1ee93cd3 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -68,10 +68,10 @@ static int write_modem(struct cardstate *cs)
struct tty_struct *tty = cs->hw.ser->tty;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct sk_buff *skb = bcs->tx_skb;
- int sent;
+ int sent = -EOPNOTSUPP;
if (!tty || !tty->driver || !skb)
- return -EFAULT;
+ return -EINVAL;
if (!skb->len) {
dev_kfree_skb_any(skb);
@@ -80,7 +80,8 @@ static int write_modem(struct cardstate *cs)
}
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, skb->data, skb->len);
+ if (tty->ops->write)
+ sent = tty->ops->write(tty, skb->data, skb->len);
gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);
if (sent < 0) {
/* error */
@@ -120,7 +121,7 @@ static int send_cb(struct cardstate *cs)
if (cb->len) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len);
+ sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len);
if (sent < 0) {
/* error */
gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);
@@ -440,14 +441,14 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsi
struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear;
- if (!tty || !tty->driver || !tty->driver->tiocmset)
- return -EFAULT;
+ if (!tty || !tty->driver || !tty->ops->tiocmset)
+ return -EINVAL;
set = new_state & ~old_state;
clear = old_state & ~new_state;
if (!set && !clear)
return 0;
gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear);
- return tty->driver->tiocmset(tty, NULL, set, clear);
+ return tty->ops->tiocmset(tty, NULL, set, clear);
}
static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 8af0df1d5b8..1a2222cbb80 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1352,12 +1352,14 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
+ lock_kernel();
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
#endif
control = info->mcr;
status = info->msr;
+ unlock_kernel();
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
@@ -1381,6 +1383,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
#endif
+ lock_kernel();
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR) {
@@ -1402,6 +1405,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
isdn_tty_modem_hup(info, 1);
}
}
+ unlock_kernel();
return 0;
}
@@ -1435,21 +1439,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
return retval;
tty_wait_until_sent(tty, 0);
return 0;
- case TIOCGSOFTCAR:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
-#endif
- return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
- case TIOCSSOFTCAR:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
-#endif
- if (get_user(arg, (ulong __user *) arg))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
@@ -1472,13 +1461,14 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!old_termios)
isdn_tty_change_speed(info);
else {
- if (tty->termios->c_cflag == old_termios->c_cflag)
+ if (tty->termios->c_cflag == old_termios->c_cflag &&
+ tty->termios->c_ispeed == old_termios->c_ispeed &&
+ tty->termios->c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios->c_cflag & CRTSCTS))
tty->hw_stopped = 0;
- }
}
}
@@ -1718,9 +1708,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
}
dev->modempoll--;
isdn_tty_shutdown(info);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ isdn_tty_flush_buffer(tty);
tty_ldisc_flush(tty);
info->tty = NULL;
info->ncarrier = 0;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index bb3e4b1cb77..83eb78b0013 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -276,6 +276,7 @@ static mddev_t * mddev_find(dev_t unit)
init_waitqueue_head(&new->sb_wait);
new->reshape_position = MaxSector;
new->resync_max = MaxSector;
+ new->level = LEVEL_NONE;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
@@ -1369,6 +1370,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
MD_BUG();
return -EINVAL;
}
+
+ /* prevent duplicates */
+ if (find_rdev(mddev, rdev->bdev->bd_dev))
+ return -EEXIST;
+
/* make sure rdev->size exceeds mddev->size */
if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) {
if (mddev->pers) {
@@ -1652,6 +1658,8 @@ static void md_update_sb(mddev_t * mddev, int force_change)
int sync_req;
int nospares = 0;
+ if (mddev->external)
+ return;
repeat:
spin_lock_irq(&mddev->write_lock);
@@ -1820,6 +1828,10 @@ state_show(mdk_rdev_t *rdev, char *page)
len += sprintf(page+len, "%swrite_mostly",sep);
sep = ",";
}
+ if (test_bit(Blocked, &rdev->flags)) {
+ len += sprintf(page+len, "%sblocked", sep);
+ sep = ",";
+ }
if (!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags)) {
len += sprintf(page+len, "%sspare", sep);
@@ -1836,6 +1848,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
* remove - disconnects the device
* writemostly - sets write_mostly
* -writemostly - clears write_mostly
+ * blocked - sets the Blocked flag
+ * -blocked - clears the Blocked flag
*/
int err = -EINVAL;
if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
@@ -1858,6 +1872,16 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
} else if (cmd_match(buf, "-writemostly")) {
clear_bit(WriteMostly, &rdev->flags);
err = 0;
+ } else if (cmd_match(buf, "blocked")) {
+ set_bit(Blocked, &rdev->flags);
+ err = 0;
+ } else if (cmd_match(buf, "-blocked")) {
+ clear_bit(Blocked, &rdev->flags);
+ wake_up(&rdev->blocked_wait);
+ set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+ md_wakeup_thread(rdev->mddev->thread);
+
+ err = 0;
}
return err ? err : len;
}
@@ -2097,7 +2121,7 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
rv = -EBUSY;
else
rv = entry->store(rdev, page, length);
- mddev_unlock(rdev->mddev);
+ mddev_unlock(mddev);
}
return rv;
}
@@ -2186,7 +2210,9 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
goto abort_free;
}
}
+
INIT_LIST_HEAD(&rdev->same_set);
+ init_waitqueue_head(&rdev->blocked_wait);
return rdev;
@@ -2457,7 +2483,6 @@ resync_start_show(mddev_t *mddev, char *page)
static ssize_t
resync_start_store(mddev_t *mddev, const char *buf, size_t len)
{
- /* can only set chunk_size if array is not yet active */
char *e;
unsigned long long n = simple_strtoull(buf, &e, 10);
@@ -2591,15 +2616,20 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
err = do_md_stop(mddev, 1);
else {
mddev->ro = 1;
+ set_disk_ro(mddev->gendisk, 1);
err = do_md_run(mddev);
}
break;
case read_auto:
- /* stopping an active array */
if (mddev->pers) {
- err = do_md_stop(mddev, 1);
- if (err == 0)
- mddev->ro = 2; /* FIXME mark devices writable */
+ if (mddev->ro != 1)
+ err = do_md_stop(mddev, 1);
+ else
+ err = restart_array(mddev);
+ if (err == 0) {
+ mddev->ro = 2;
+ set_disk_ro(mddev->gendisk, 0);
+ }
} else {
mddev->ro = 2;
err = do_md_run(mddev);
@@ -2612,6 +2642,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
if (atomic_read(&mddev->writes_pending) == 0) {
if (mddev->in_sync == 0) {
mddev->in_sync = 1;
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
if (mddev->persistent)
set_bit(MD_CHANGE_CLEAN,
&mddev->flags);
@@ -2635,6 +2667,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
err = 0;
} else {
mddev->ro = 0;
+ set_disk_ro(mddev->gendisk, 0);
err = do_md_run(mddev);
}
break;
@@ -3712,6 +3745,30 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->reshape_position = MaxSector;
mddev->external = 0;
mddev->persistent = 0;
+ mddev->level = LEVEL_NONE;
+ mddev->clevel[0] = 0;
+ mddev->flags = 0;
+ mddev->ro = 0;
+ mddev->metadata_type[0] = 0;
+ mddev->chunk_size = 0;
+ mddev->ctime = mddev->utime = 0;
+ mddev->layout = 0;
+ mddev->max_disks = 0;
+ mddev->events = 0;
+ mddev->delta_disks = 0;
+ mddev->new_level = LEVEL_NONE;
+ mddev->new_layout = 0;
+ mddev->new_chunk = 0;
+ mddev->curr_resync = 0;
+ mddev->resync_mismatches = 0;
+ mddev->suspend_lo = mddev->suspend_hi = 0;
+ mddev->sync_speed_min = mddev->sync_speed_max = 0;
+ mddev->recovery = 0;
+ mddev->in_sync = 0;
+ mddev->changed = 0;
+ mddev->degraded = 0;
+ mddev->barriers_work = 0;
+ mddev->safemode = 0;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4919,6 +4976,9 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
if (!rdev || test_bit(Faulty, &rdev->flags))
return;
+
+ if (mddev->external)
+ set_bit(Blocked, &rdev->flags);
/*
dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
mdname(mddev),
@@ -5365,6 +5425,8 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
md_wakeup_thread(mddev->sync_thread);
}
atomic_inc(&mddev->writes_pending);
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
if (mddev->in_sync) {
spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) {
@@ -5719,7 +5781,7 @@ static int remove_and_add_spares(mddev_t *mddev)
rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
- !mddev->external &&
+ !test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
atomic_read(&rdev->nr_pending)==0) {
@@ -5789,7 +5851,7 @@ void md_check_recovery(mddev_t *mddev)
return;
if (signal_pending(current)) {
- if (mddev->pers->sync_request) {
+ if (mddev->pers->sync_request && !mddev->external) {
printk(KERN_INFO "md: %s in immediate safe mode\n",
mdname(mddev));
mddev->safemode = 2;
@@ -5801,7 +5863,7 @@ void md_check_recovery(mddev_t *mddev)
(mddev->flags && !mddev->external) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
- (mddev->safemode == 1) ||
+ (mddev->external == 0 && mddev->safemode == 1) ||
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
&& !mddev->in_sync && mddev->recovery_cp == MaxSector)
))
@@ -5810,16 +5872,20 @@ void md_check_recovery(mddev_t *mddev)
if (mddev_trylock(mddev)) {
int spares = 0;
- spin_lock_irq(&mddev->write_lock);
- if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
- !mddev->in_sync && mddev->recovery_cp == MaxSector) {
- mddev->in_sync = 1;
- if (mddev->persistent)
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (!mddev->external) {
+ spin_lock_irq(&mddev->write_lock);
+ if (mddev->safemode &&
+ !atomic_read(&mddev->writes_pending) &&
+ !mddev->in_sync &&
+ mddev->recovery_cp == MaxSector) {
+ mddev->in_sync = 1;
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
+ spin_unlock_irq(&mddev->write_lock);
}
- if (mddev->safemode == 1)
- mddev->safemode = 0;
- spin_unlock_irq(&mddev->write_lock);
if (mddev->flags)
md_update_sb(mddev, 0);
@@ -5914,6 +5980,16 @@ void md_check_recovery(mddev_t *mddev)
}
}
+void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
+{
+ sysfs_notify(&rdev->kobj, NULL, "state");
+ wait_event_timeout(rdev->blocked_wait,
+ !test_bit(Blocked, &rdev->flags),
+ msecs_to_jiffies(5000));
+ rdev_dec_pending(rdev, mddev);
+}
+EXPORT_SYMBOL(md_wait_for_blocked_rdev);
+
static int md_notify_reboot(struct notifier_block *this,
unsigned long code, void *x)
{
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 9fd473a6dbf..6778b7cb39b 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -773,7 +773,6 @@ static int make_request(struct request_queue *q, struct bio * bio)
r1bio_t *r1_bio;
struct bio *read_bio;
int i, targets = 0, disks;
- mdk_rdev_t *rdev;
struct bitmap *bitmap = mddev->bitmap;
unsigned long flags;
struct bio_list bl;
@@ -781,6 +780,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
const int rw = bio_data_dir(bio);
const int do_sync = bio_sync(bio);
int do_barriers;
+ mdk_rdev_t *blocked_rdev;
/*
* Register the new request and wait if the reconstruction
@@ -862,10 +862,17 @@ static int make_request(struct request_queue *q, struct bio * bio)
first = 0;
}
#endif
+ retry_write:
+ blocked_rdev = NULL;
rcu_read_lock();
for (i = 0; i < disks; i++) {
- if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL &&
- !test_bit(Faulty, &rdev->flags)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ atomic_inc(&rdev->nr_pending);
+ blocked_rdev = rdev;
+ break;
+ }
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
if (test_bit(Faulty, &rdev->flags)) {
rdev_dec_pending(rdev, mddev);
@@ -878,6 +885,20 @@ static int make_request(struct request_queue *q, struct bio * bio)
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ /* Wait for this device to become unblocked */
+ int j;
+
+ for (j = 0; j < i; j++)
+ if (r1_bio->bios[j])
+ rdev_dec_pending(conf->mirrors[j].rdev, mddev);
+
+ allow_barrier(conf);
+ md_wait_for_blocked_rdev(blocked_rdev, mddev);
+ wait_barrier(conf);
+ goto retry_write;
+ }
+
BUG_ON(targets == 0); /* we never fail the last device */
if (targets < conf->raid_disks) {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1e96aa3ff51..5938fa96292 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -790,6 +790,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
const int do_sync = bio_sync(bio);
struct bio_list bl;
unsigned long flags;
+ mdk_rdev_t *blocked_rdev;
if (unlikely(bio_barrier(bio))) {
bio_endio(bio, -EOPNOTSUPP);
@@ -879,17 +880,23 @@ static int make_request(struct request_queue *q, struct bio * bio)
/*
* WRITE:
*/
- /* first select target devices under spinlock and
+ /* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
* bios[x] to bio
*/
raid10_find_phys(conf, r10_bio);
+ retry_write:
+ blocked_rdev = 0;
rcu_read_lock();
for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev &&
- !test_bit(Faulty, &rdev->flags)) {
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ atomic_inc(&rdev->nr_pending);
+ blocked_rdev = rdev;
+ break;
+ }
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
r10_bio->devs[i].bio = bio;
} else {
@@ -899,6 +906,22 @@ static int make_request(struct request_queue *q, struct bio * bio)
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ /* Have to wait for this device to get unblocked, then retry */
+ int j;
+ int d;
+
+ for (j = 0; j < i; j++)
+ if (r10_bio->devs[j].bio) {
+ d = r10_bio->devs[j].devnum;
+ rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+ }
+ allow_barrier(conf);
+ md_wait_for_blocked_rdev(blocked_rdev, mddev);
+ wait_barrier(conf);
+ goto retry_write;
+ }
+
atomic_set(&r10_bio->remaining, 0);
bio_list_init(&bl);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 968dacaced6..087eee0cb80 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2607,6 +2607,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
}
}
+
/*
* handle_stripe - do things to a stripe.
*
@@ -2632,6 +2633,7 @@ static void handle_stripe5(struct stripe_head *sh)
struct stripe_head_state s;
struct r5dev *dev;
unsigned long pending = 0;
+ mdk_rdev_t *blocked_rdev = NULL;
memset(&s, 0, sizeof(s));
pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d "
@@ -2691,6 +2693,11 @@ static void handle_stripe5(struct stripe_head *sh)
if (dev->written)
s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ blocked_rdev = rdev;
+ atomic_inc(&rdev->nr_pending);
+ break;
+ }
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
clear_bit(R5_ReadError, &dev->flags);
@@ -2705,6 +2712,11 @@ static void handle_stripe5(struct stripe_head *sh)
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ set_bit(STRIPE_HANDLE, &sh->state);
+ goto unlock;
+ }
+
if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending))
sh->ops.count++;
@@ -2894,8 +2906,13 @@ static void handle_stripe5(struct stripe_head *sh)
if (sh->ops.count)
pending = get_stripe_work(sh);
+ unlock:
spin_unlock(&sh->lock);
+ /* wait for this device to become unblocked */
+ if (unlikely(blocked_rdev))
+ md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+
if (pending)
raid5_run_ops(sh, pending);
@@ -2912,6 +2929,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
struct stripe_head_state s;
struct r6_state r6s;
struct r5dev *dev, *pdev, *qdev;
+ mdk_rdev_t *blocked_rdev = NULL;
r6s.qd_idx = raid6_next_disk(pd_idx, disks);
pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
@@ -2975,6 +2993,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
if (dev->written)
s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ blocked_rdev = rdev;
+ atomic_inc(&rdev->nr_pending);
+ break;
+ }
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
clear_bit(R5_ReadError, &dev->flags);
@@ -2989,6 +3012,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
set_bit(R5_Insync, &dev->flags);
}
rcu_read_unlock();
+
+ if (unlikely(blocked_rdev)) {
+ set_bit(STRIPE_HANDLE, &sh->state);
+ goto unlock;
+ }
pr_debug("locked=%d uptodate=%d to_read=%d"
" to_write=%d failed=%d failed_num=%d,%d\n",
s.locked, s.uptodate, s.to_read, s.to_write, s.failed,
@@ -3094,8 +3122,13 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
!test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
handle_stripe_expansion(conf, sh, &r6s);
+ unlock:
spin_unlock(&sh->lock);
+ /* wait for this device to become unblocked */
+ if (unlikely(blocked_rdev))
+ md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+
return_io(return_bi);
for (i=disks; i-- ;) {
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 8e744823064..351b98b9b30 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -2,6 +2,7 @@ saa7146-objs := saa7146_i2c.o saa7146_core.o
saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
+obj-y += tuners/
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 03816b73f84..27da7b42327 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -81,8 +81,6 @@
/* Limits scaled width, which must be a multiple of 4. */
#define MAX_HACTIVE (0x3FF & -4)
-#define clamp(x, low, high) min (max (low, x), high)
-
#define BTTV_NORMS (\
V4L2_STD_PAL | V4L2_STD_PAL_N | \
V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 64819353276..17f542dfb36 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -70,12 +70,6 @@
#define VICAM_HEADER_SIZE 64
-#define clamp( x, l, h ) max_t( __typeof__( x ), \
- ( l ), \
- min_t( __typeof__( x ), \
- ( h ), \
- ( x ) ) )
-
/* Not sure what all the bytes in these char
* arrays do, but they're necessary to make
* the camera work.
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index f6f2d960cad..ef8a492766a 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -132,7 +132,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
if (iter >= MAX_ASIC_ISR_LOOPS)
printk(KERN_ERR "%s: interrupt processing overrun\n",
- __FUNCTION__);
+ __func__);
}
static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
@@ -409,7 +409,7 @@ int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio)
return asic3_get_gpio_d(asic, Status) & mask;
default:
printk(KERN_ERR "%s: invalid GPIO value 0x%x",
- __FUNCTION__, gpio);
+ __func__, gpio);
return -EINVAL;
}
}
@@ -437,7 +437,7 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val)
return;
default:
printk(KERN_ERR "%s: invalid GPIO value 0x%x",
- __FUNCTION__, gpio);
+ __func__, gpio);
return;
}
}
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 6e655b4c668..2fe64734d8a 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -349,11 +349,11 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
mode &= 3; /* get current power mode */
if (unit >= ARRAY_SIZE(sm->unit_power)) {
- dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit);
+ dev_err(dev, "%s: bad unit %d\n", __func__, unit);
goto already;
}
- dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit,
+ dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __func__, unit,
sm->unit_power[unit], to);
if (to == 0 && sm->unit_power[unit] == 0) {
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 6d6286c4eea..30a1af857c7 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -132,7 +132,7 @@ static int send_ack;
static int final_ack;
static int hw_break_val;
static int hw_break_val2;
-#if defined(CONFIG_ARM) || defined(CONFIG_MIPS)
+#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
static int arch_needs_sstep_emulation = 1;
#else
static int arch_needs_sstep_emulation;
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 9c6573419f5..fdfb2b2cb73 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -670,7 +670,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
}
skb->protocol = eth_type_trans(skb,dev);
- adapter->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
}
@@ -773,12 +773,12 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
* received board statistics
*/
case CMD_NETWORK_STATISTICS_RESPONSE:
- adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
- adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
- adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
- adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
- adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
- adapter->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
+ dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
+ dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
+ dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
+ dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
+ dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
+ dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
adapter->got[CMD_NETWORK_STATISTICS] = 1;
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);
@@ -794,11 +794,11 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
break;
switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
case 0xffff:
- adapter->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);
break;
case 0xfffe:
- adapter->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
break;
}
@@ -986,7 +986,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb)
return false;
}
- adapter->stats.tx_bytes += nlen;
+ dev->stats.tx_bytes += nlen;
/*
* send the adapter a transmit packet command. Ignore segment and offset
@@ -1041,7 +1041,6 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb)
static void elp_timeout(struct net_device *dev)
{
- elp_device *adapter = dev->priv;
int stat;
stat = inb_status(dev->base_addr);
@@ -1049,7 +1048,7 @@ static void elp_timeout(struct net_device *dev)
if (elp_debug >= 1)
printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat);
dev->trans_start = jiffies;
- adapter->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1113,7 +1112,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
/* If the device is closed, just return the latest stats we have,
- we cannot ask from the adapter without interrupts */
if (!netif_running(dev))
- return &adapter->stats;
+ return &dev->stats;
/* send a get statistics command to the board */
adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
@@ -1126,12 +1125,12 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
- return &adapter->stats;
+ return &dev->stats;
}
}
/* statistics are now up to date */
- return &adapter->stats;
+ return &dev->stats;
}
@@ -1571,7 +1570,6 @@ static int __init elplus_setup(struct net_device *dev)
dev->set_multicast_list = elp_set_mc_list; /* local */
dev->ethtool_ops = &netdev_ethtool_ops; /* local */
- memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
dev->mem_start = dev->mem_end = 0;
err = register_netdev(dev);
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
index 1910cb1dc78..04df2a9002b 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/3c505.h
@@ -264,7 +264,6 @@ typedef struct {
pcb_struct rx_pcb; /* PCB for foreground receiving */
pcb_struct itx_pcb; /* PCB for background sending */
pcb_struct irx_pcb; /* PCB for background receiving */
- struct net_device_stats stats;
void *dma_buffer;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 54dac0696d9..e6c545fe5f5 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -167,7 +167,6 @@ enum RxFilter {
enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
struct el3_private {
- struct net_device_stats stats;
spinlock_t lock;
/* skb send-queue */
int head, size;
@@ -794,7 +793,6 @@ el3_open(struct net_device *dev)
static void
el3_tx_timeout (struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
@@ -802,7 +800,7 @@ el3_tx_timeout (struct net_device *dev)
"Tx FIFO room %d.\n",
dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
inw(ioaddr + TX_FREE));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
dev->trans_start = jiffies;
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
@@ -820,7 +818,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue (dev);
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
if (el3_debug > 4) {
printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
@@ -881,7 +879,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i = 4;
while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@@ -931,12 +929,11 @@ el3_interrupt(int irq, void *dev_id)
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
}
if (status & TxComplete) { /* Really Tx error. */
- struct el3_private *lp = netdev_priv(dev);
short tx_status;
int i = 4;
while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@@ -1002,7 +999,7 @@ el3_get_stats(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
update_stats(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return &lp->stats;
+ return &dev->stats;
}
/* Update statistics. We change to register window 6, so this should be run
@@ -1012,7 +1009,6 @@ el3_get_stats(struct net_device *dev)
*/
static void update_stats(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
if (el3_debug > 5)
@@ -1021,13 +1017,13 @@ static void update_stats(struct net_device *dev)
outw(StatsDisable, ioaddr + EL3_CMD);
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- lp->stats.tx_carrier_errors += inb(ioaddr + 0);
- lp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- lp->stats.collisions += inb(ioaddr + 3);
- lp->stats.tx_window_errors += inb(ioaddr + 4);
- lp->stats.rx_fifo_errors += inb(ioaddr + 5);
- lp->stats.tx_packets += inb(ioaddr + 6);
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
/* Rx packets */ inb(ioaddr + 7);
/* Tx deferrals */ inb(ioaddr + 8);
inw(ioaddr + 10); /* Total Rx and Tx octets. */
@@ -1042,7 +1038,6 @@ static void update_stats(struct net_device *dev)
static int
el3_rx(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
short rx_status;
@@ -1054,21 +1049,21 @@ el3_rx(struct net_device *dev)
short error = rx_status & 0x3800;
outw(RxDiscard, ioaddr + EL3_CMD);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
switch (error) {
- case 0x0000: lp->stats.rx_over_errors++; break;
- case 0x0800: lp->stats.rx_length_errors++; break;
- case 0x1000: lp->stats.rx_frame_errors++; break;
- case 0x1800: lp->stats.rx_length_errors++; break;
- case 0x2000: lp->stats.rx_frame_errors++; break;
- case 0x2800: lp->stats.rx_crc_errors++; break;
+ case 0x0000: dev->stats.rx_over_errors++; break;
+ case 0x0800: dev->stats.rx_length_errors++; break;
+ case 0x1000: dev->stats.rx_frame_errors++; break;
+ case 0x1800: dev->stats.rx_length_errors++; break;
+ case 0x2000: dev->stats.rx_frame_errors++; break;
+ case 0x2800: dev->stats.rx_crc_errors++; break;
}
} else {
short pkt_len = rx_status & 0x7ff;
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1083,11 +1078,11 @@ el3_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
continue;
}
outw(RxDiscard, ioaddr + EL3_CMD);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
if (el3_debug)
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, pkt_len);
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 6ab84b661d7..105a8c7ca7e 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -310,7 +310,6 @@ struct corkscrew_private {
struct sk_buff *tx_skbuff[TX_RING_SIZE];
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
- struct net_device_stats stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
struct timer_list timer; /* Media selection timer. */
int capabilities ; /* Adapter capabilities word. */
@@ -983,8 +982,8 @@ static void corkscrew_timeout(struct net_device *dev)
break;
outw(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies;
- vp->stats.tx_errors++;
- vp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1050,7 +1049,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
- vp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
@@ -1094,9 +1093,9 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
printk("%s: Tx error, status %2.2x.\n",
dev->name, tx_status);
if (tx_status & 0x04)
- vp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (tx_status & 0x38)
- vp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
@@ -1257,7 +1256,6 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
static int corkscrew_rx(struct net_device *dev)
{
- struct corkscrew_private *vp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int i;
short rx_status;
@@ -1271,17 +1269,17 @@ static int corkscrew_rx(struct net_device *dev)
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
- vp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_error & 0x01)
- vp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rx_error & 0x02)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_error & 0x04)
- vp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
- vp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
@@ -1301,8 +1299,8 @@ static int corkscrew_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
- vp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1312,7 +1310,7 @@ static int corkscrew_rx(struct net_device *dev)
printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
}
outw(RxDiscard, ioaddr + EL3_CMD);
- vp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
/* Wait a limited time to skip this packet. */
for (i = 200; i >= 0; i--)
if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1337,23 +1335,23 @@ static int boomerang_rx(struct net_device *dev)
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
- vp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_error & 0x01)
- vp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rx_error & 0x02)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_error & 0x04)
- vp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
- vp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
- vp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
if (corkscrew_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1388,7 +1386,7 @@ static int boomerang_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
@@ -1475,7 +1473,7 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
update_stats(dev->base_addr, dev);
spin_unlock_irqrestore(&vp->lock, flags);
}
- return &vp->stats;
+ return &dev->stats;
}
/* Update statistics.
@@ -1487,19 +1485,17 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
*/
static void update_stats(int ioaddr, struct net_device *dev)
{
- struct corkscrew_private *vp = netdev_priv(dev);
-
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- vp->stats.tx_carrier_errors += inb(ioaddr + 0);
- vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- vp->stats.collisions += inb(ioaddr + 3);
- vp->stats.tx_window_errors += inb(ioaddr + 4);
- vp->stats.rx_fifo_errors += inb(ioaddr + 5);
- vp->stats.tx_packets += inb(ioaddr + 6);
- vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
+ dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
/* Rx packets */ inb(ioaddr + 7);
/* Must read to clear */
/* Tx deferrals */ inb(ioaddr + 8);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f90a86ba7e2..af46341827f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2593,6 +2593,7 @@ config BNX2X
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
+source "drivers/net/sfc/Kconfig"
endif # NETDEV_10000
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 2f1f3f2739f..dcbfe842115 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -253,3 +253,5 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+obj-$(CONFIG_SFC) += sfc/
+
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index f9cc2b621fe..8eda6eeb43b 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -47,3 +47,11 @@ config EP93XX_ETH
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices.
+
+config IXP4XX_ETH
+ tristate "Intel IXP4xx Ethernet support"
+ depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+ select MII
+ help
+ Say Y here if you want to use built-in Ethernet ports
+ on IXP4xx processor.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
index a4c868278e1..7c812ac2b6a 100644
--- a/drivers/net/arm/Makefile
+++ b/drivers/net/arm/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_ARM_ETHER3) += ether3.o
obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
+obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
new file mode 100644
index 00000000000..c617b64c288
--- /dev/null
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -0,0 +1,1265 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port 0x00 0x10 0x20
+ * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
+ * physical PortId 2 0 1
+ * TX queue 23 24 25
+ * RX-free queue 26 27 28
+ * TX-done queue is always 31, per-port RX and TX-ready queues are configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1 - NPE ID (RX and TX-done)
+ * bits 0 -> 2 - priority (TX, per 802.1D)
+ * bits 3 -> 4 - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/etherdevice.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/platform_device.h>
+#include <asm/arch/npe.h>
+#include <asm/arch/qmgr.h>
+
+#define DEBUG_QUEUES 0
+#define DEBUG_DESC 0
+#define DEBUG_RX 0
+#define DEBUG_TX 0
+#define DEBUG_PKT_BYTES 0
+#define DEBUG_MDIO 0
+#define DEBUG_CLOSE 0
+
+#define DRV_NAME "ixp4xx_eth"
+
+#define MAX_NPES 3
+
+#define RX_DESCS 64 /* also length of all RX queues */
+#define TX_DESCS 16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN 64 /* dwords */
+
+#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
+#define REGS_SIZE 0x1000
+#define MAX_MRU 1536 /* 0x600 */
+#define RX_BUFF_SIZE ALIGN((NET_IP_ALIGN) + MAX_MRU, 4)
+
+#define NAPI_WEIGHT 16
+#define MDIO_INTERVAL (3 * HZ)
+#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
+#define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */
+#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
+
+#define NPE_ID(port_id) ((port_id) >> 4)
+#define PHYSICAL_ID(port_id) ((NPE_ID(port_id) + 2) % 3)
+#define TX_QUEUE(port_id) (NPE_ID(port_id) + 23)
+#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
+#define TXDONE_QUEUE 31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN 0x01
+#define TX_CNTRL0_HALFDUPLEX 0x02
+#define TX_CNTRL0_RETRY 0x04
+#define TX_CNTRL0_PAD_EN 0x08
+#define TX_CNTRL0_APPEND_FCS 0x10
+#define TX_CNTRL0_2DEFER 0x20
+#define TX_CNTRL0_RMII 0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN 0x01
+#define RX_CNTRL0_PADSTRIP_EN 0x02
+#define RX_CNTRL0_SEND_FCS 0x04
+#define RX_CNTRL0_PAUSE_EN 0x08
+#define RX_CNTRL0_LOOP_EN 0x10
+#define RX_CNTRL0_ADDR_FLTR_EN 0x20
+#define RX_CNTRL0_RX_RUNT_EN 0x40
+#define RX_CNTRL0_BCAST_DIS 0x80
+#define RX_CNTRL1_DEFER_EN 0x01
+
+/* Core Control Register */
+#define CORE_RESET 0x01
+#define CORE_RX_FIFO_FLUSH 0x02
+#define CORE_TX_FIFO_FLUSH 0x04
+#define CORE_SEND_JAM 0x08
+#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
+ TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+ TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS 0x00
+#define NPE_EDB_SETPORTADDRESS 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
+#define NPE_GETSTATS 0x04
+#define NPE_RESETSTATS 0x05
+#define NPE_SETMAXFRAMELENGTHS 0x06
+#define NPE_VLAN_SETRXTAGMODE 0x07
+#define NPE_VLAN_SETDEFAULTRXVID 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
+#define NPE_VLAN_SETRXQOSENTRY 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE 0x0D
+#define NPE_FW_SETFIREWALLMODE 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE 0x11
+#define NPE_SETLOOPBACK_MODE 0x12
+#define NPE_PC_SETBSSIDTABLE 0x13
+#define NPE_ADDRESS_FILTER_CONFIG 0x14
+#define NPE_APPENDFCSCONFIG 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
+#define NPE_MAC_RECOVERY_START 0x17
+
+
+#ifdef __ARMEB__
+typedef struct sk_buff buffer_t;
+#define free_buffer dev_kfree_skb
+#define free_buffer_irq dev_kfree_skb_irq
+#else
+typedef void buffer_t;
+#define free_buffer kfree
+#define free_buffer_irq kfree
+#endif
+
+struct eth_regs {
+ u32 tx_control[2], __res1[2]; /* 000 */
+ u32 rx_control[2], __res2[2]; /* 010 */
+ u32 random_seed, __res3[3]; /* 020 */
+ u32 partial_empty_threshold, __res4; /* 030 */
+ u32 partial_full_threshold, __res5; /* 038 */
+ u32 tx_start_bytes, __res6[3]; /* 040 */
+ u32 tx_deferral, rx_deferral, __res7[2];/* 050 */
+ u32 tx_2part_deferral[2], __res8[2]; /* 060 */
+ u32 slot_time, __res9[3]; /* 070 */
+ u32 mdio_command[4]; /* 080 */
+ u32 mdio_status[4]; /* 090 */
+ u32 mcast_mask[6], __res10[2]; /* 0A0 */
+ u32 mcast_addr[6], __res11[2]; /* 0C0 */
+ u32 int_clock_threshold, __res12[3]; /* 0E0 */
+ u32 hw_addr[6], __res13[61]; /* 0F0 */
+ u32 core_control; /* 1FC */
+};
+
+struct port {
+ struct resource *mem_res;
+ struct eth_regs __iomem *regs;
+ struct npe *npe;
+ struct net_device *netdev;
+ struct napi_struct napi;
+ struct net_device_stats stat;
+ struct mii_if_info mii;
+ struct delayed_work mdio_thread;
+ struct eth_plat_info *plat;
+ buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
+ struct desc *desc_tab; /* coherent */
+ u32 desc_tab_phys;
+ int id; /* logical port ID */
+ u16 mii_bmcr;
+};
+
+/* NPE message structure */
+struct msg {
+#ifdef __ARMEB__
+ u8 cmd, eth_id, byte2, byte3;
+ u8 byte4, byte5, byte6, byte7;
+#else
+ u8 byte3, byte2, eth_id, cmd;
+ u8 byte7, byte6, byte5, byte4;
+#endif
+};
+
+/* Ethernet packet descriptor */
+struct desc {
+ u32 next; /* pointer to next buffer, unused */
+
+#ifdef __ARMEB__
+ u16 buf_len; /* buffer length */
+ u16 pkt_len; /* packet length */
+ u32 data; /* pointer to data buffer in RAM */
+ u8 dest_id;
+ u8 src_id;
+ u16 flags;
+ u8 qos;
+ u8 padlen;
+ u16 vlan_tci;
+#else
+ u16 pkt_len; /* packet length */
+ u16 buf_len; /* buffer length */
+ u32 data; /* pointer to data buffer in RAM */
+ u16 flags;
+ u8 src_id;
+ u8 dest_id;
+ u16 vlan_tci;
+ u8 padlen;
+ u8 qos;
+#endif
+
+#ifdef __ARMEB__
+ u8 dst_mac_0, dst_mac_1, dst_mac_2, dst_mac_3;
+ u8 dst_mac_4, dst_mac_5, src_mac_0, src_mac_1;
+ u8 src_mac_2, src_mac_3, src_mac_4, src_mac_5;
+#else
+ u8 dst_mac_3, dst_mac_2, dst_mac_1, dst_mac_0;
+ u8 src_mac_1, src_mac_0, dst_mac_5, dst_mac_4;
+ u8 src_mac_5, src_mac_4, src_mac_3, src_mac_2;
+#endif
+};
+
+
+#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
+ (n) * sizeof(struct desc))
+#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
+
+#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
+ ((n) + RX_DESCS) * sizeof(struct desc))
+#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
+
+#ifndef __ARMEB__
+static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
+{
+ int i;
+ for (i = 0; i < cnt; i++)
+ dest[i] = swab32(src[i]);
+}
+#endif
+
+static spinlock_t mdio_lock;
+static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
+static int ports_open;
+static struct port *npe_port_tab[MAX_NPES];
+static struct dma_pool *dma_pool;
+
+
+static u16 mdio_cmd(struct net_device *dev, int phy_id, int location,
+ int write, u16 cmd)
+{
+ int cycles = 0;
+
+ if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+ printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name);
+ return 0;
+ }
+
+ if (write) {
+ __raw_writel(cmd & 0xFF, &mdio_regs->mdio_command[0]);
+ __raw_writel(cmd >> 8, &mdio_regs->mdio_command[1]);
+ }
+ __raw_writel(((phy_id << 5) | location) & 0xFF,
+ &mdio_regs->mdio_command[2]);
+ __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+ &mdio_regs->mdio_command[3]);
+
+ while ((cycles < MAX_MDIO_RETRIES) &&
+ (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_MDIO_RETRIES) {
+ printk(KERN_ERR "%s: MII write failed\n", dev->name);
+ return 0;
+ }
+
+#if DEBUG_MDIO
+ printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name,
+ cycles);
+#endif
+
+ if (write)
+ return 0;
+
+ if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+ printk(KERN_ERR "%s: MII read failed\n", dev->name);
+ return 0;
+ }
+
+ return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+ (__raw_readl(&mdio_regs->mdio_status[1]) << 8);
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ unsigned long flags;
+ u16 val;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ val = mdio_cmd(dev, phy_id, location, 0, 0);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ return val;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+ int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ mdio_cmd(dev, phy_id, location, 1, val);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+}
+
+static void phy_reset(struct net_device *dev, int phy_id)
+{
+ struct port *port = netdev_priv(dev);
+ int cycles = 0;
+
+ mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);
+
+ while (cycles < MAX_MII_RESET_RETRIES) {
+ if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
+#if DEBUG_MDIO
+ printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n",
+ dev->name, cycles);
+#endif
+ return;
+ }
+ udelay(1);
+ cycles++;
+ }
+
+ printk(KERN_ERR "%s: MII reset failed\n", dev->name);
+}
+
+static void eth_set_duplex(struct port *port)
+{
+ if (port->mii.full_duplex)
+ __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+ else
+ __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+}
+
+
+static void phy_check_media(struct port *port, int init)
+{
+ if (mii_check_media(&port->mii, 1, init))
+ eth_set_duplex(port);
+ if (port->mii.force_media) { /* mii_check_media() doesn't work */
+ struct net_device *dev = port->netdev;
+ int cur_link = mii_link_ok(&port->mii);
+ int prev_link = netif_carrier_ok(dev);
+
+ if (!prev_link && cur_link) {
+ printk(KERN_INFO "%s: link up\n", dev->name);
+ netif_carrier_on(dev);
+ } else if (prev_link && !cur_link) {
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ netif_carrier_off(dev);
+ }
+ }
+}
+
+
+static void mdio_thread(struct work_struct *work)
+{
+ struct port *port = container_of(work, struct port, mdio_thread.work);
+
+ phy_check_media(port, 0);
+ schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+}
+
+
+static inline void debug_pkt(struct net_device *dev, const char *func,
+ u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+ int i;
+
+ printk(KERN_DEBUG "%s: %s(%i) ", dev->name, func, len);
+ for (i = 0; i < len; i++) {
+ if (i >= DEBUG_PKT_BYTES)
+ break;
+ printk("%s%02X",
+ ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+ data[i]);
+ }
+ printk("\n");
+#endif
+}
+
+
+static inline void debug_desc(u32 phys, struct desc *desc)
+{
+#if DEBUG_DESC
+ printk(KERN_DEBUG "%X: %X %3X %3X %08X %2X < %2X %4X %X"
+ " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+ phys, desc->next, desc->buf_len, desc->pkt_len,
+ desc->data, desc->dest_id, desc->src_id, desc->flags,
+ desc->qos, desc->padlen, desc->vlan_tci,
+ desc->dst_mac_0, desc->dst_mac_1, desc->dst_mac_2,
+ desc->dst_mac_3, desc->dst_mac_4, desc->dst_mac_5,
+ desc->src_mac_0, desc->src_mac_1, desc->src_mac_2,
+ desc->src_mac_3, desc->src_mac_4, desc->src_mac_5);
+#endif
+}
+
+static inline void debug_queue(unsigned int queue, int is_get, u32 phys)
+{
+#if DEBUG_QUEUES
+ static struct {
+ int queue;
+ char *name;
+ } names[] = {
+ { TX_QUEUE(0x10), "TX#0 " },
+ { TX_QUEUE(0x20), "TX#1 " },
+ { TX_QUEUE(0x00), "TX#2 " },
+ { RXFREE_QUEUE(0x10), "RX-free#0 " },
+ { RXFREE_QUEUE(0x20), "RX-free#1 " },
+ { RXFREE_QUEUE(0x00), "RX-free#2 " },
+ { TXDONE_QUEUE, "TX-done " },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(names); i++)
+ if (names[i].queue == queue)
+ break;
+
+ printk(KERN_DEBUG "Queue %i %s%s %X\n", queue,
+ i < ARRAY_SIZE(names) ? names[i].name : "",
+ is_get ? "->" : "<-", phys);
+#endif
+}
+
+static inline u32 queue_get_entry(unsigned int queue)
+{
+ u32 phys = qmgr_get_entry(queue);
+ debug_queue(queue, 1, phys);
+ return phys;
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+ int is_tx)
+{
+ u32 phys, tab_phys, n_desc;
+ struct desc *tab;
+
+ if (!(phys = queue_get_entry(queue)))
+ return -1;
+
+ phys &= ~0x1F; /* mask out non-address bits */
+ tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0);
+ tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0);
+ n_desc = (phys - tab_phys) / sizeof(struct desc);
+ BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS));
+ debug_desc(phys, &tab[n_desc]);
+ BUG_ON(tab[n_desc].next);
+ return n_desc;
+}
+
+static inline void queue_put_desc(unsigned int queue, u32 phys,
+ struct desc *desc)
+{
+ debug_queue(queue, 0, phys);
+ debug_desc(phys, desc);
+ BUG_ON(phys & 0x1F);
+ qmgr_put_entry(queue, phys);
+ BUG_ON(qmgr_stat_overflow(queue));
+}
+
+
+static inline void dma_unmap_tx(struct port *port, struct desc *desc)
+{
+#ifdef __ARMEB__
+ dma_unmap_single(&port->netdev->dev, desc->data,
+ desc->buf_len, DMA_TO_DEVICE);
+#else
+ dma_unmap_single(&port->netdev->dev, desc->data & ~3,
+ ALIGN((desc->data & 3) + desc->buf_len, 4),
+ DMA_TO_DEVICE);
+#endif
+}
+
+
+static void eth_rx_irq(void *pdev)
+{
+ struct net_device *dev = pdev;
+ struct port *port = netdev_priv(dev);
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name);
+#endif
+ qmgr_disable_irq(port->plat->rxq);
+ netif_rx_schedule(dev, &port->napi);
+}
+
+static int eth_poll(struct napi_struct *napi, int budget)
+{
+ struct port *port = container_of(napi, struct port, napi);
+ struct net_device *dev = port->netdev;
+ unsigned int rxq = port->plat->rxq, rxfreeq = RXFREE_QUEUE(port->id);
+ int received = 0;
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll\n", dev->name);
+#endif
+
+ while (received < budget) {
+ struct sk_buff *skb;
+ struct desc *desc;
+ int n;
+#ifdef __ARMEB__
+ struct sk_buff *temp;
+ u32 phys;
+#endif
+
+ if ((n = queue_get_desc(rxq, port, 0)) < 0) {
+ received = 0; /* No packet received */
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n",
+ dev->name);
+#endif
+ netif_rx_complete(dev, napi);
+ qmgr_enable_irq(rxq);
+ if (!qmgr_stat_empty(rxq) &&
+ netif_rx_reschedule(dev, napi)) {
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll"
+ " netif_rx_reschedule successed\n",
+ dev->name);
+#endif
+ qmgr_disable_irq(rxq);
+ continue;
+ }
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll all done\n",
+ dev->name);
+#endif
+ return 0; /* all work done */
+ }
+
+ desc = rx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+ if ((skb = netdev_alloc_skb(dev, RX_BUFF_SIZE))) {
+ phys = dma_map_single(&dev->dev, skb->data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(phys)) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+#else
+ skb = netdev_alloc_skb(dev,
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4));
+#endif
+
+ if (!skb) {
+ port->stat.rx_dropped++;
+ /* put the desc back on RX-ready queue */
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+ continue;
+ }
+
+ /* process received frame */
+#ifdef __ARMEB__
+ temp = skb;
+ skb = port->rx_buff_tab[n];
+ dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+#else
+ dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4);
+#endif
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, desc->pkt_len);
+
+ debug_pkt(dev, "eth_poll", skb->data, skb->len);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+ port->stat.rx_packets++;
+ port->stat.rx_bytes += skb->len;
+ netif_receive_skb(skb);
+
+ /* put the new buffer on RX-free queue */
+#ifdef __ARMEB__
+ port->rx_buff_tab[n] = temp;
+ desc->data = phys + NET_IP_ALIGN;
+#endif
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+ received++;
+ }
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "eth_poll(): end, not all work done\n");
+#endif
+ return received; /* not all work done */
+}
+
+
+static void eth_txdone_irq(void *unused)
+{
+ u32 phys;
+
+#if DEBUG_TX
+ printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n");
+#endif
+ while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) {
+ u32 npe_id, n_desc;
+ struct port *port;
+ struct desc *desc;
+ int start;
+
+ npe_id = phys & 3;
+ BUG_ON(npe_id >= MAX_NPES);
+ port = npe_port_tab[npe_id];
+ BUG_ON(!port);
+ phys &= ~0x1F; /* mask out non-address bits */
+ n_desc = (phys - tx_desc_phys(port, 0)) / sizeof(struct desc);
+ BUG_ON(n_desc >= TX_DESCS);
+ desc = tx_desc_ptr(port, n_desc);
+ debug_desc(phys, desc);
+
+ if (port->tx_buff_tab[n_desc]) { /* not the draining packet */
+ port->stat.tx_packets++;
+ port->stat.tx_bytes += desc->pkt_len;
+
+ dma_unmap_tx(port, desc);
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_txdone_irq free %p\n",
+ port->netdev->name, port->tx_buff_tab[n_desc]);
+#endif
+ free_buffer_irq(port->tx_buff_tab[n_desc]);
+ port->tx_buff_tab[n_desc] = NULL;
+ }
+
+ start = qmgr_stat_empty(port->plat->txreadyq);
+ queue_put_desc(port->plat->txreadyq, phys, desc);
+ if (start) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n",
+ port->netdev->name);
+#endif
+ netif_wake_queue(port->netdev);
+ }
+ }
+}
+
+static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ unsigned int txreadyq = port->plat->txreadyq;
+ int len, offset, bytes, n;
+ void *mem;
+ u32 phys;
+ struct desc *desc;
+
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit\n", dev->name);
+#endif
+
+ if (unlikely(skb->len > MAX_MRU)) {
+ dev_kfree_skb(skb);
+ port->stat.tx_errors++;
+ return NETDEV_TX_OK;
+ }
+
+ debug_pkt(dev, "eth_xmit", skb->data, skb->len);
+
+ len = skb->len;
+#ifdef __ARMEB__
+ offset = 0; /* no need to keep alignment */
+ bytes = len;
+ mem = skb->data;
+#else
+ offset = (int)skb->data & 3; /* keep 32-bit alignment */
+ bytes = ALIGN(offset + len, 4);
+ if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
+ dev_kfree_skb(skb);
+ port->stat.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+ memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
+ dev_kfree_skb(skb);
+#endif
+
+ phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(phys)) {
+#ifdef __ARMEB__
+ dev_kfree_skb(skb);
+#else
+ kfree(mem);
+#endif
+ port->stat.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ n = queue_get_desc(txreadyq, port, 1);
+ BUG_ON(n < 0);
+ desc = tx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+ port->tx_buff_tab[n] = skb;
+#else
+ port->tx_buff_tab[n] = mem;
+#endif
+ desc->data = phys + offset;
+ desc->buf_len = desc->pkt_len = len;
+
+ /* NPE firmware pads short frames with zeros internally */
+ wmb();
+ queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
+ dev->trans_start = jiffies;
+
+ if (qmgr_stat_empty(txreadyq)) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name);
+#endif
+ netif_stop_queue(dev);
+ /* we could miss TX ready interrupt */
+ if (!qmgr_stat_empty(txreadyq)) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit ready again\n",
+ dev->name);
+#endif
+ netif_wake_queue(dev);
+ }
+ }
+
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
+#endif
+ return NETDEV_TX_OK;
+}
+
+
+static struct net_device_stats *eth_stats(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ return &port->stat;
+}
+
+static void eth_set_mcast_list(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct dev_mc_list *mclist = dev->mc_list;
+ u8 diffs[ETH_ALEN], *addr;
+ int cnt = dev->mc_count, i;
+
+ if ((dev->flags & IFF_PROMISC) || !mclist || !cnt) {
+ __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+ return;
+ }
+
+ memset(diffs, 0, ETH_ALEN);
+ addr = mclist->dmi_addr; /* first MAC address */
+
+ while (--cnt && (mclist = mclist->next))
+ for (i = 0; i < ETH_ALEN; i++)
+ diffs[i] |= addr[i] ^ mclist->dmi_addr[i];
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ __raw_writel(addr[i], &port->regs->mcast_addr[i]);
+ __raw_writel(~diffs[i], &port->regs->mcast_mask[i]);
+ }
+
+ __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+}
+
+
+static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ struct port *port = netdev_priv(dev);
+ unsigned int duplex_chg;
+ int err;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+ err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
+ if (duplex_chg)
+ eth_set_duplex(port);
+ return err;
+}
+
+
+static int request_queues(struct port *port)
+{
+ int err;
+
+ err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0);
+ if (err)
+ return err;
+
+ err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0);
+ if (err)
+ goto rel_rxfree;
+
+ err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0);
+ if (err)
+ goto rel_rx;
+
+ err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0);
+ if (err)
+ goto rel_tx;
+
+ /* TX-done queue handles skbs sent out by the NPEs */
+ if (!ports_open) {
+ err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0);
+ if (err)
+ goto rel_txready;
+ }
+ return 0;
+
+rel_txready:
+ qmgr_release_queue(port->plat->txreadyq);
+rel_tx:
+ qmgr_release_queue(TX_QUEUE(port->id));
+rel_rx:
+ qmgr_release_queue(port->plat->rxq);
+rel_rxfree:
+ qmgr_release_queue(RXFREE_QUEUE(port->id));
+ printk(KERN_DEBUG "%s: unable to request hardware queues\n",
+ port->netdev->name);
+ return err;
+}
+
+static void release_queues(struct port *port)
+{
+ qmgr_release_queue(RXFREE_QUEUE(port->id));
+ qmgr_release_queue(port->plat->rxq);
+ qmgr_release_queue(TX_QUEUE(port->id));
+ qmgr_release_queue(port->plat->txreadyq);
+
+ if (!ports_open)
+ qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static int init_queues(struct port *port)
+{
+ int i;
+
+ if (!ports_open)
+ if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
+ POOL_ALLOC_SIZE, 32, 0)))
+ return -ENOMEM;
+
+ if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
+ &port->desc_tab_phys)))
+ return -ENOMEM;
+ memset(port->desc_tab, 0, POOL_ALLOC_SIZE);
+ memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */
+ memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab));
+
+ /* Setup RX buffers */
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff; /* skb or kmalloc()ated memory */
+ void *data;
+#ifdef __ARMEB__
+ if (!(buff = netdev_alloc_skb(port->netdev, RX_BUFF_SIZE)))
+ return -ENOMEM;
+ data = buff->data;
+#else
+ if (!(buff = kmalloc(RX_BUFF_SIZE, GFP_KERNEL)))
+ return -ENOMEM;
+ data = buff;
+#endif
+ desc->buf_len = MAX_MRU;
+ desc->data = dma_map_single(&port->netdev->dev, data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(desc->data)) {
+ free_buffer(buff);
+ return -EIO;
+ }
+ desc->data += NET_IP_ALIGN;
+ port->rx_buff_tab[i] = buff;
+ }
+
+ return 0;
+}
+
+static void destroy_queues(struct port *port)
+{
+ int i;
+
+ if (port->desc_tab) {
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff = port->rx_buff_tab[i];
+ if (buff) {
+ dma_unmap_single(&port->netdev->dev,
+ desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ free_buffer(buff);
+ }
+ }
+ for (i = 0; i < TX_DESCS; i++) {
+ struct desc *desc = tx_desc_ptr(port, i);
+ buffer_t *buff = port->tx_buff_tab[i];
+ if (buff) {
+ dma_unmap_tx(port, desc);
+ free_buffer(buff);
+ }
+ }
+ dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys);
+ port->desc_tab = NULL;
+ }
+
+ if (!ports_open && dma_pool) {
+ dma_pool_destroy(dma_pool);
+ dma_pool = NULL;
+ }
+}
+
+static int eth_open(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct npe *npe = port->npe;
+ struct msg msg;
+ int i, err;
+
+ if (!npe_running(npe)) {
+ err = npe_load_firmware(npe, npe_name(npe), &dev->dev);
+ if (err)
+ return err;
+
+ if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+ printk(KERN_ERR "%s: %s not responding\n", dev->name,
+ npe_name(npe));
+ return -EIO;
+ }
+ }
+
+ mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+ msg.eth_id = port->id;
+ msg.byte5 = port->plat->rxq | 0x80;
+ msg.byte7 = port->plat->rxq << 4;
+ for (i = 0; i < 8; i++) {
+ msg.byte3 = i;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ"))
+ return -EIO;
+ }
+
+ msg.cmd = NPE_EDB_SETPORTADDRESS;
+ msg.eth_id = PHYSICAL_ID(port->id);
+ msg.byte2 = dev->dev_addr[0];
+ msg.byte3 = dev->dev_addr[1];
+ msg.byte4 = dev->dev_addr[2];
+ msg.byte5 = dev->dev_addr[3];
+ msg.byte6 = dev->dev_addr[4];
+ msg.byte7 = dev->dev_addr[5];
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC"))
+ return -EIO;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_FW_SETFIREWALLMODE;
+ msg.eth_id = port->id;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE"))
+ return -EIO;
+
+ if ((err = request_queues(port)) != 0)
+ return err;
+
+ if ((err = init_queues(port)) != 0) {
+ destroy_queues(port);
+ release_queues(port);
+ return err;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
+ __raw_writel(0x08, &port->regs->random_seed);
+ __raw_writel(0x12, &port->regs->partial_empty_threshold);
+ __raw_writel(0x30, &port->regs->partial_full_threshold);
+ __raw_writel(0x08, &port->regs->tx_start_bytes);
+ __raw_writel(0x15, &port->regs->tx_deferral);
+ __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+ __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+ __raw_writel(0x80, &port->regs->slot_time);
+ __raw_writel(0x01, &port->regs->int_clock_threshold);
+
+ /* Populate queues with buffers, no failure after this point */
+ for (i = 0; i < TX_DESCS; i++)
+ queue_put_desc(port->plat->txreadyq,
+ tx_desc_phys(port, i), tx_desc_ptr(port, i));
+
+ for (i = 0; i < RX_DESCS; i++)
+ queue_put_desc(RXFREE_QUEUE(port->id),
+ rx_desc_phys(port, i), rx_desc_ptr(port, i));
+
+ __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+ __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+ __raw_writel(0, &port->regs->rx_control[1]);
+ __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+ napi_enable(&port->napi);
+ phy_check_media(port, 1);
+ eth_set_mcast_list(dev);
+ netif_start_queue(dev);
+ schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+
+ qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_rx_irq, dev);
+ if (!ports_open) {
+ qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_txdone_irq, NULL);
+ qmgr_enable_irq(TXDONE_QUEUE);
+ }
+ ports_open++;
+ /* we may already have RX data, enables IRQ */
+ netif_rx_schedule(dev, &port->napi);
+ return 0;
+}
+
+static int eth_close(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct msg msg;
+ int buffs = RX_DESCS; /* allocated RX buffers */
+ int i;
+
+ ports_open--;
+ qmgr_disable_irq(port->plat->rxq);
+ napi_disable(&port->napi);
+ netif_stop_queue(dev);
+
+ while (queue_get_desc(RXFREE_QUEUE(port->id), port, 0) >= 0)
+ buffs--;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_SETLOOPBACK_MODE;
+ msg.eth_id = port->id;
+ msg.byte3 = 1;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+ printk(KERN_CRIT "%s: unable to enable loopback\n", dev->name);
+
+ i = 0;
+ do { /* drain RX buffers */
+ while (queue_get_desc(port->plat->rxq, port, 0) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ if (qmgr_stat_empty(TX_QUEUE(port->id))) {
+ /* we have to inject some packet */
+ struct desc *desc;
+ u32 phys;
+ int n = queue_get_desc(port->plat->txreadyq, port, 1);
+ BUG_ON(n < 0);
+ desc = tx_desc_ptr(port, n);
+ phys = tx_desc_phys(port, n);
+ desc->buf_len = desc->pkt_len = 1;
+ wmb();
+ queue_put_desc(TX_QUEUE(port->id), phys, desc);
+ }
+ udelay(1);
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)"
+ " left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ printk(KERN_DEBUG "Draining RX queue took %i cycles\n", i);
+#endif
+
+ buffs = TX_DESCS;
+ while (queue_get_desc(TX_QUEUE(port->id), port, 1) >= 0)
+ buffs--; /* cancel TX */
+
+ i = 0;
+ do {
+ while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) "
+ "left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i);
+#endif
+
+ msg.byte3 = 0;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+ printk(KERN_CRIT "%s: unable to disable loopback\n",
+ dev->name);
+
+ port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &
+ ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */
+ mdio_write(dev, port->plat->phy, MII_BMCR,
+ port->mii_bmcr | BMCR_PDOWN);
+
+ if (!ports_open)
+ qmgr_disable_irq(TXDONE_QUEUE);
+ cancel_rearming_delayed_work(&port->mdio_thread);
+ destroy_queues(port);
+ release_queues(port);
+ return 0;
+}
+
+static int __devinit eth_init_one(struct platform_device *pdev)
+{
+ struct port *port;
+ struct net_device *dev;
+ struct eth_plat_info *plat = pdev->dev.platform_data;
+ u32 regs_phys;
+ int err;
+
+ if (!(dev = alloc_etherdev(sizeof(struct port))))
+ return -ENOMEM;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ port = netdev_priv(dev);
+ port->netdev = dev;
+ port->id = pdev->id;
+
+ switch (port->id) {
+ case IXP4XX_ETH_NPEA:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthA_BASE_VIRT;
+ regs_phys = IXP4XX_EthA_BASE_PHYS;
+ break;
+ case IXP4XX_ETH_NPEB:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+ regs_phys = IXP4XX_EthB_BASE_PHYS;
+ break;
+ case IXP4XX_ETH_NPEC:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
+ regs_phys = IXP4XX_EthC_BASE_PHYS;
+ break;
+ default:
+ err = -ENOSYS;
+ goto err_free;
+ }
+
+ dev->open = eth_open;
+ dev->hard_start_xmit = eth_xmit;
+ dev->stop = eth_close;
+ dev->get_stats = eth_stats;
+ dev->do_ioctl = eth_ioctl;
+ dev->set_multicast_list = eth_set_mcast_list;
+ dev->tx_queue_len = 100;
+
+ netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT);
+
+ if (!(port->npe = npe_request(NPE_ID(port->id)))) {
+ err = -EIO;
+ goto err_free;
+ }
+
+ if (register_netdev(dev)) {
+ err = -EIO;
+ goto err_npe_rel;
+ }
+
+ port->mem_res = request_mem_region(regs_phys, REGS_SIZE, dev->name);
+ if (!port->mem_res) {
+ err = -EBUSY;
+ goto err_unreg;
+ }
+
+ port->plat = plat;
+ npe_port_tab[NPE_ID(port->id)] = port;
+ memcpy(dev->dev_addr, plat->hwaddr, ETH_ALEN);
+
+ platform_set_drvdata(pdev, dev);
+
+ __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+ &port->regs->core_control);
+ udelay(50);
+ __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+ udelay(50);
+
+ port->mii.dev = dev;
+ port->mii.mdio_read = mdio_read;
+ port->mii.mdio_write = mdio_write;
+ port->mii.phy_id = plat->phy;
+ port->mii.phy_id_mask = 0x1F;
+ port->mii.reg_num_mask = 0x1F;
+
+ printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
+ npe_name(port->npe));
+
+ phy_reset(dev, plat->phy);
+ port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &
+ ~(BMCR_RESET | BMCR_PDOWN);
+ mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);
+
+ INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
+ return 0;
+
+err_unreg:
+ unregister_netdev(dev);
+err_npe_rel:
+ npe_release(port->npe);
+err_free:
+ free_netdev(dev);
+ return err;
+}
+
+static int __devexit eth_remove_one(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct port *port = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ npe_port_tab[NPE_ID(port->id)] = NULL;
+ platform_set_drvdata(pdev, NULL);
+ npe_release(port->npe);
+ release_resource(port->mem_res);
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver drv = {
+ .driver.name = DRV_NAME,
+ .probe = eth_init_one,
+ .remove = eth_remove_one,
+};
+
+static int __init eth_init_module(void)
+{
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+ return -ENOSYS;
+
+ /* All MII PHY accesses use NPE-B Ethernet registers */
+ spin_lock_init(&mdio_lock);
+ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+ __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+ return platform_driver_register(&drv);
+}
+
+static void __exit eth_cleanup_module(void)
+{
+ platform_driver_unregister(&drv);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_DESCRIPTION("Intel IXP4xx Ethernet driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ixp4xx_eth");
+module_init(eth_init_module);
+module_exit(eth_cleanup_module);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 4fec8581bfd..89c0018132e 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -27,6 +27,7 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
@@ -42,7 +43,7 @@
#define DRV_NAME "bfin_mac"
#define DRV_VERSION "1.1"
#define DRV_AUTHOR "Bryan Wu, Luke Yang"
-#define DRV_DESC "Blackfin BF53[67] BF527 on-chip Ethernet MAC driver"
+#define DRV_DESC "Blackfin on-chip Ethernet MAC driver"
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -73,8 +74,14 @@ static struct net_dma_desc_tx *current_tx_ptr;
static struct net_dma_desc_tx *tx_desc;
static struct net_dma_desc_rx *rx_desc;
-static void bf537mac_disable(void);
-static void bf537mac_enable(void);
+#if defined(CONFIG_BFIN_MAC_RMII)
+static u16 pin_req[] = P_RMII0;
+#else
+static u16 pin_req[] = P_MII0;
+#endif
+
+static void bfin_mac_disable(void);
+static void bfin_mac_enable(void);
static void desc_list_free(void)
{
@@ -243,27 +250,6 @@ init_error:
/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
-/* Set FER regs to MUX in Ethernet pins */
-static int setup_pin_mux(int action)
-{
-#if defined(CONFIG_BFIN_MAC_RMII)
- u16 pin_req[] = P_RMII0;
-#else
- u16 pin_req[] = P_MII0;
-#endif
-
- if (action) {
- if (peripheral_request_list(pin_req, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
- return -EFAULT;
- }
- } else
- peripheral_free_list(pin_req);
-
- return 0;
-}
-
/*
* MII operations
*/
@@ -322,9 +308,9 @@ static int mdiobus_reset(struct mii_bus *bus)
return 0;
}
-static void bf537_adjust_link(struct net_device *dev)
+static void bfin_mac_adjust_link(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = lp->phydev;
unsigned long flags;
int new_state = 0;
@@ -395,7 +381,7 @@ static void bf537_adjust_link(struct net_device *dev)
static int mii_probe(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = NULL;
unsigned short sysctl;
int i;
@@ -431,10 +417,10 @@ static int mii_probe(struct net_device *dev)
}
#if defined(CONFIG_BFIN_MAC_RMII)
- phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_RMII);
#else
- phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
#endif
@@ -469,6 +455,51 @@ static int mii_probe(struct net_device *dev)
return 0;
}
+/*
+ * Ethtool support
+ */
+
+static int
+bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
+ if (lp->phydev)
+ return phy_ethtool_gset(lp->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static int
+bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (lp->phydev)
+ return phy_ethtool_sset(lp->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+ strcpy(info->bus_info, dev->dev.bus_id);
+}
+
+static struct ethtool_ops bfin_mac_ethtool_ops = {
+ .get_settings = bfin_mac_ethtool_getsettings,
+ .set_settings = bfin_mac_ethtool_setsettings,
+ .get_link = ethtool_op_get_link,
+ .get_drvinfo = bfin_mac_ethtool_getdrvinfo,
+};
+
/**************************************************************************/
void setup_system_regs(struct net_device *dev)
{
@@ -511,7 +542,7 @@ static void setup_mac_addr(u8 *mac_addr)
bfin_write_EMAC_ADDRHI(addr_hi);
}
-static int bf537mac_set_mac_address(struct net_device *dev, void *p)
+static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
@@ -573,7 +604,7 @@ adjust_head:
}
-static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
unsigned int data;
@@ -631,7 +662,7 @@ out:
return 0;
}
-static void bf537mac_rx(struct net_device *dev)
+static void bfin_mac_rx(struct net_device *dev)
{
struct sk_buff *skb, *new_skb;
unsigned short len;
@@ -680,7 +711,7 @@ out:
}
/* interrupt routine to handle rx and error signal */
-static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+static irqreturn_t bfin_mac_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
int number = 0;
@@ -700,21 +731,21 @@ get_one_packet:
}
real_rx:
- bf537mac_rx(dev);
+ bfin_mac_rx(dev);
number++;
goto get_one_packet;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-static void bf537mac_poll(struct net_device *dev)
+static void bfin_mac_poll(struct net_device *dev)
{
disable_irq(IRQ_MAC_RX);
- bf537mac_interrupt(IRQ_MAC_RX, dev);
+ bfin_mac_interrupt(IRQ_MAC_RX, dev);
enable_irq(IRQ_MAC_RX);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
-static void bf537mac_disable(void)
+static void bfin_mac_disable(void)
{
unsigned int opmode;
@@ -728,7 +759,7 @@ static void bf537mac_disable(void)
/*
* Enable Interrupts, Receive, and Transmit
*/
-static void bf537mac_enable(void)
+static void bfin_mac_enable(void)
{
u32 opmode;
@@ -766,23 +797,23 @@ static void bf537mac_enable(void)
}
/* Our watchdog timed out. Called by the networking layer */
-static void bf537mac_timeout(struct net_device *dev)
+static void bfin_mac_timeout(struct net_device *dev)
{
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
- bf537mac_disable();
+ bfin_mac_disable();
/* reset tx queue */
tx_list_tail = tx_list_head->next;
- bf537mac_enable();
+ bfin_mac_enable();
/* We can accept TX packets again */
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
-static void bf537mac_multicast_hash(struct net_device *dev)
+static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
struct dev_mc_list *dmi = dev->mc_list;
@@ -821,7 +852,7 @@ static void bf537mac_multicast_hash(struct net_device *dev)
* promiscuous mode (for TCPDUMP and cousins) or accept
* a select set of multicast packets
*/
-static void bf537mac_set_multicast_list(struct net_device *dev)
+static void bfin_mac_set_multicast_list(struct net_device *dev)
{
u32 sysctl;
@@ -840,7 +871,7 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= HM;
bfin_write_EMAC_OPMODE(sysctl);
- bf537mac_multicast_hash(dev);
+ bfin_mac_multicast_hash(dev);
} else {
/* clear promisc or multicast mode */
sysctl = bfin_read_EMAC_OPMODE();
@@ -852,7 +883,7 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
/*
* this puts the device in an inactive state
*/
-static void bf537mac_shutdown(struct net_device *dev)
+static void bfin_mac_shutdown(struct net_device *dev)
{
/* Turn off the EMAC */
bfin_write_EMAC_OPMODE(0x00000000);
@@ -866,9 +897,9 @@ static void bf537mac_shutdown(struct net_device *dev)
*
* Set up everything, reset the card, etc..
*/
-static int bf537mac_open(struct net_device *dev)
+static int bfin_mac_open(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
int retval;
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
@@ -891,8 +922,8 @@ static int bf537mac_open(struct net_device *dev)
phy_start(lp->phydev);
phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
setup_system_regs(dev);
- bf537mac_disable();
- bf537mac_enable();
+ bfin_mac_disable();
+ bfin_mac_enable();
pr_debug("hardware init finished\n");
netif_start_queue(dev);
netif_carrier_on(dev);
@@ -906,9 +937,9 @@ static int bf537mac_open(struct net_device *dev)
* and not talk to the outside world. Caused by
* an 'ifconfig ethX down'
*/
-static int bf537mac_close(struct net_device *dev)
+static int bfin_mac_close(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
@@ -918,7 +949,7 @@ static int bf537mac_close(struct net_device *dev)
phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
/* clear everything */
- bf537mac_shutdown(dev);
+ bfin_mac_shutdown(dev);
/* free the rx/tx buffers */
desc_list_free();
@@ -926,46 +957,59 @@ static int bf537mac_close(struct net_device *dev)
return 0;
}
-static int __init bf537mac_probe(struct net_device *dev)
+static int __init bfin_mac_probe(struct platform_device *pdev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
- int retval;
- int i;
+ struct net_device *ndev;
+ struct bfin_mac_local *lp;
+ int rc, i;
+
+ ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
+ if (!ndev) {
+ dev_err(&pdev->dev, "Cannot allocate net device!\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ platform_set_drvdata(pdev, ndev);
+ lp = netdev_priv(ndev);
/* Grab the MAC address in the MAC */
- *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
- *(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
+ *(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
+ *(__le16 *) (&(ndev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
/* probe mac */
/*todo: how to proble? which is revision_register */
bfin_write_EMAC_ADDRLO(0x12345678);
if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
- pr_debug("can't detect bf537 mac!\n");
- retval = -ENODEV;
- goto err_out;
+ dev_err(&pdev->dev, "Cannot detect Blackfin on-chip ethernet MAC controller!\n");
+ rc = -ENODEV;
+ goto out_err_probe_mac;
}
/* set the GPIO pins to Ethernet mode */
- retval = setup_pin_mux(1);
- if (retval)
- return retval;
-
- /*Is it valid? (Did bootloader initialize it?) */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- /* Grab the MAC from the board somehow - this is done in the
- arch/blackfin/mach-bf537/boards/eth_mac.c */
- bfin_get_ether_addr(dev->dev_addr);
+ rc = peripheral_request_list(pin_req, DRV_NAME);
+ if (rc) {
+ dev_err(&pdev->dev, "Requesting peripherals failed!\n");
+ rc = -EFAULT;
+ goto out_err_setup_pin_mux;
}
+ /*
+ * Is it valid? (Did bootloader initialize it?)
+ * Grab the MAC from the board somehow
+ * this is done in the arch/blackfin/mach-bfxxx/boards/eth_mac.c
+ */
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ bfin_get_ether_addr(ndev->dev_addr);
+
/* If still not valid, get a random one */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- random_ether_addr(dev->dev_addr);
- }
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ random_ether_addr(ndev->dev_addr);
- setup_mac_addr(dev->dev_addr);
+ setup_mac_addr(ndev->dev_addr);
/* MDIO bus initial */
- lp->mii_bus.priv = dev;
+ lp->mii_bus.priv = ndev;
lp->mii_bus.read = mdiobus_read;
lp->mii_bus.write = mdiobus_write;
lp->mii_bus.reset = mdiobus_reset;
@@ -975,86 +1019,86 @@ static int __init bf537mac_probe(struct net_device *dev)
for (i = 0; i < PHY_MAX_ADDR; ++i)
lp->mii_bus.irq[i] = PHY_POLL;
- mdiobus_register(&lp->mii_bus);
+ rc = mdiobus_register(&lp->mii_bus);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
+ goto out_err_mdiobus_register;
+ }
- retval = mii_probe(dev);
- if (retval)
- return retval;
+ rc = mii_probe(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "MII Probe failed!\n");
+ goto out_err_mii_probe;
+ }
/* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
-
- dev->open = bf537mac_open;
- dev->stop = bf537mac_close;
- dev->hard_start_xmit = bf537mac_hard_start_xmit;
- dev->set_mac_address = bf537mac_set_mac_address;
- dev->tx_timeout = bf537mac_timeout;
- dev->set_multicast_list = bf537mac_set_multicast_list;
+ ether_setup(ndev);
+
+ ndev->open = bfin_mac_open;
+ ndev->stop = bfin_mac_close;
+ ndev->hard_start_xmit = bfin_mac_hard_start_xmit;
+ ndev->set_mac_address = bfin_mac_set_mac_address;
+ ndev->tx_timeout = bfin_mac_timeout;
+ ndev->set_multicast_list = bfin_mac_set_multicast_list;
#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = bf537mac_poll;
+ ndev->poll_controller = bfin_mac_poll;
#endif
+ ndev->ethtool_ops = &bfin_mac_ethtool_ops;
spin_lock_init(&lp->lock);
/* now, enable interrupts */
/* register irq handler */
- if (request_irq
- (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
- "EMAC_RX", dev)) {
- printk(KERN_WARNING DRV_NAME
- ": Unable to attach BlackFin MAC RX interrupt\n");
- return -EBUSY;
+ rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
+ rc = -EBUSY;
+ goto out_err_request_irq;
}
-
- retval = register_netdev(dev);
- if (retval == 0) {
- /* now, print out the card info, in a short format.. */
- printk(KERN_INFO "%s: Version %s, %s\n",
- DRV_NAME, DRV_VERSION, DRV_DESC);
- }
-
-err_out:
- return retval;
-}
-
-static int bfin_mac_probe(struct platform_device *pdev)
-{
- struct net_device *ndev;
-
- ndev = alloc_etherdev(sizeof(struct bf537mac_local));
- if (!ndev) {
- printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
- return -ENOMEM;
+ rc = register_netdev(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register net device!\n");
+ goto out_err_reg_ndev;
}
- SET_NETDEV_DEV(ndev, &pdev->dev);
+ /* now, print out the card info, in a short format.. */
+ dev_info(&pdev->dev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
- platform_set_drvdata(pdev, ndev);
+ return 0;
- if (bf537mac_probe(ndev) != 0) {
- platform_set_drvdata(pdev, NULL);
- free_netdev(ndev);
- printk(KERN_WARNING DRV_NAME ": not found\n");
- return -ENODEV;
- }
+out_err_reg_ndev:
+ free_irq(IRQ_MAC_RX, ndev);
+out_err_request_irq:
+out_err_mii_probe:
+ mdiobus_unregister(&lp->mii_bus);
+out_err_mdiobus_register:
+ peripheral_free_list(pin_req);
+out_err_setup_pin_mux:
+out_err_probe_mac:
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
- return 0;
+ return rc;
}
static int bfin_mac_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct bfin_mac_local *lp = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL);
+ mdiobus_unregister(&lp->mii_bus);
+
unregister_netdev(ndev);
free_irq(IRQ_MAC_RX, ndev);
free_netdev(ndev);
- setup_pin_mux(0);
+ peripheral_free_list(pin_req);
return 0;
}
@@ -1065,7 +1109,7 @@ static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
- bf537mac_close(net_dev);
+ bfin_mac_close(net_dev);
return 0;
}
@@ -1075,7 +1119,7 @@ static int bfin_mac_resume(struct platform_device *pdev)
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
- bf537mac_open(net_dev);
+ bfin_mac_open(net_dev);
return 0;
}
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index f774d5a3694..beff51064ff 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -49,7 +49,7 @@ struct net_dma_desc_tx {
struct status_area_tx status;
};
-struct bf537mac_local {
+struct bfin_mac_local {
/*
* these are things that the kernel wants me to keep, so users
* can find out semi-useless statistics of how well the card is
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 83bda6ccde9..56f50491a45 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -633,7 +633,7 @@ static void __init printEEPROMInfo(struct net_device *dev)
printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
- printk(KERN_DEBUG " AutoPort: %d\n", GetBit(!Word,ee_Jabber));
+ printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
}
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index e5e6352556f..d21b7ab64bd 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -491,20 +491,23 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
out_be32(&fec->ievent, ievent); /* clear pending events */
- if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
- if (ievent & ~FEC_IEVENT_TFINT)
- dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
+ /* on fifo error, soft-reset fec */
+ if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+
+ if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
+ if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+
+ mpc52xx_fec_reset(dev);
+
+ netif_wake_queue(dev);
return IRQ_HANDLED;
}
- if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
- dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
- if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
- dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+ if (ievent & ~FEC_IEVENT_TFINT)
+ dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
- mpc52xx_fec_reset(dev);
-
- netif_wake_queue(dev);
return IRQ_HANDLED;
}
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 99a4b990939..587afe7be68 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -131,8 +131,6 @@ static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
-extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value);
-extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct napi_struct *napi, int budget);
#endif
@@ -477,24 +475,30 @@ static int init_phy(struct net_device *dev)
return 0;
}
+/*
+ * Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip. We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the TBIPA register. We assume
+ * that the TBIPA register is valid. Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
static void gfar_configure_serdes(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_mii __iomem *regs =
(void __iomem *)&priv->regs->gfar_mii_regs;
+ int tbipa = gfar_read(&priv->regs->tbipa);
- /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+ /* Single clk mode, mii mode off(for serdes communication) */
+ gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT);
- /* Single clk mode, mii mode off(for aerdes communication) */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
-
- /* Supported pause and full-duplex, no half-duplex */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+ gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE,
ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
ADVERTISE_1000XPSE_ASYM);
- /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+ gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE |
BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
}
@@ -541,9 +545,6 @@ static void init_registers(struct net_device *dev)
/* Initialize the Minimum Frame Length Register */
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
-
- /* Assign the TBI an address which won't conflict with the PHYs */
- gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 0d088360946..fd487be3993 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -137,7 +137,6 @@ extern const char gfar_driver_version[];
#define DEFAULT_RXCOUNT 0
#endif /* CONFIG_GFAR_NAPI */
-#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
#define MIIMCFG_RESET 0x80000000
#define MIIMIND_BUSY 0x00000001
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index b8898927236..ebcfb27a904 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -78,7 +78,6 @@ int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
* same as system mdio bus, used for controlling the external PHYs, for eg.
*/
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
-
{
u16 value;
@@ -122,7 +121,7 @@ int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
}
/* Reset the MIIM registers, and wait for the bus to free */
-int gfar_mdio_reset(struct mii_bus *bus)
+static int gfar_mdio_reset(struct mii_bus *bus)
{
struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
@@ -152,14 +151,15 @@ int gfar_mdio_reset(struct mii_bus *bus)
}
-int gfar_mdio_probe(struct device *dev)
+static int gfar_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gianfar_mdio_data *pdata;
struct gfar_mii __iomem *regs;
+ struct gfar __iomem *enet_regs;
struct mii_bus *new_bus;
struct resource *r;
- int err = 0;
+ int i, err = 0;
if (NULL == dev)
return -EINVAL;
@@ -199,6 +199,34 @@ int gfar_mdio_probe(struct device *dev)
new_bus->dev = dev;
dev_set_drvdata(dev, new_bus);
+ /*
+ * This is mildly evil, but so is our hardware for doing this.
+ * Also, we have to cast back to struct gfar_mii because of
+ * definition weirdness done in gianfar.h.
+ */
+ enet_regs = (struct gfar __iomem *)
+ ((char *)regs - offsetof(struct gfar, gfar_mii_regs));
+
+ /* Scan the bus, looking for an empty spot for TBIPA */
+ gfar_write(&enet_regs->tbipa, 0);
+ for (i = PHY_MAX_ADDR; i > 0; i--) {
+ u32 phy_id;
+ int r;
+
+ r = get_phy_id(new_bus, i, &phy_id);
+ if (r)
+ return r;
+
+ if (phy_id == 0xffffffff)
+ break;
+ }
+
+ /* The bus is full. We don't support using 31 PHYs, sorry */
+ if (i == 0)
+ return -EBUSY;
+
+ gfar_write(&enet_regs->tbipa, i);
+
err = mdiobus_register(new_bus);
if (0 != err) {
@@ -218,7 +246,7 @@ reg_map_fail:
}
-int gfar_mdio_remove(struct device *dev)
+static int gfar_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index b373091c703..2af28b16a0e 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -41,6 +41,9 @@ struct gfar_mii {
int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
+ int regnum, u16 value);
+int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
int __init gfar_mdio_init(void);
void gfar_mdio_exit(void);
#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 1da55dd2a5a..9d5721287d6 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -148,13 +148,13 @@ static void sp_xmit_on_air(unsigned long channel)
if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->status2 = 0;
} else
mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
@@ -220,13 +220,13 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
*/
if (sp->duplex == 1) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, count);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
sp->xleft = count - actual;
sp->xhead = sp->xbuff + actual;
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
} else {
sp->xleft = count;
sp->xhead = sp->xbuff;
@@ -444,7 +444,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
}
if (sp->tx_enable) {
- actual = tty->driver->write(tty, sp->xhead, sp->xleft);
+ actual = tty->ops->write(tty, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
}
@@ -491,9 +491,7 @@ static void sixpack_receive_buf(struct tty_struct *tty,
sixpack_decode(sp, buf, count1);
sp_put(sp);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
/*
@@ -554,8 +552,8 @@ static void resync_tnc(unsigned long channel)
/* resync the TNC */
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
- sp->tty->driver->write(sp->tty, &resync_cmd, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &resync_cmd, 1);
/* Start resync timer again -- the TNC might be still absent */
@@ -573,7 +571,7 @@ static inline int tnc_init(struct sixpack *sp)
tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
- sp->tty->driver->write(sp->tty, &inbyte, 1);
+ sp->tty->ops->write(sp->tty, &inbyte, 1);
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
@@ -601,6 +599,8 @@ static int sixpack_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
if (!dev) {
@@ -914,9 +914,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
} else { /* output watchdog char if idle */
if ((sp->status2 != 0) && (sp->duplex == 1)) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
@@ -926,7 +926,7 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
}
/* needed to trigger the TNC watchdog */
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
/* if the state byte has been received, the TNC is present,
so the resync timer can be reset. */
@@ -956,12 +956,12 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd)
if ((sp->status & SIXP_RX_DCD_MASK) ==
SIXP_RX_DCD_MASK) {
sp->led_state = 0x68;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
}
} else {
sp->led_state = 0x60;
/* fill trailing bytes with zeroes */
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
rest = sp->rx_count;
if (rest != 0)
for (i = rest; i <= 3; i++)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 30c9b3b0d13..65166035aca 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -516,7 +516,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
spin_unlock_bh(&ax->buflock);
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
- actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
+ actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
ax->stats.tx_packets++;
ax->stats.tx_bytes += actual;
@@ -546,7 +546,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
}
printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,
- (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ?
+ (ax->tty->ops->chars_in_buffer(ax->tty) || ax->xleft) ?
"bad line quality" : "driver error");
ax->xleft = 0;
@@ -736,6 +736,8 @@ static int mkiss_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
if (!dev) {
@@ -754,8 +756,7 @@ static int mkiss_open(struct tty_struct *tty)
tty->disc_data = ax;
tty->receive_room = 65535;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/* Restore default settings */
dev->type = ARPHRD_AX25;
@@ -935,9 +936,7 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
mkiss_put(ax);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
/*
@@ -962,7 +961,7 @@ static void mkiss_write_wakeup(struct tty_struct *tty)
goto out;
}
- actual = tty->driver->write(tty, ax->xhead, ax->xleft);
+ actual = tty->ops->write(tty, ax->xhead, ax->xleft);
ax->xleft -= actual;
ax->xhead += actual;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index fc753d7f674..e6f40b7f904 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -64,7 +64,7 @@ static int irtty_chars_in_buffer(struct sir_dev *dev)
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
- return priv->tty->driver->chars_in_buffer(priv->tty);
+ return tty_chars_in_buffer(priv->tty);
}
/* Wait (sleep) until underlaying hardware finished transmission
@@ -93,10 +93,8 @@ static void irtty_wait_until_sent(struct sir_dev *dev)
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
tty = priv->tty;
- if (tty->driver->wait_until_sent) {
- lock_kernel();
- tty->driver->wait_until_sent(tty, msecs_to_jiffies(100));
- unlock_kernel();
+ if (tty->ops->wait_until_sent) {
+ tty->ops->wait_until_sent(tty, msecs_to_jiffies(100));
}
else {
msleep(USBSERIAL_TX_DONE_DELAY);
@@ -125,48 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty;
- lock_kernel();
+ mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
-
- cflag &= ~CBAUD;
-
- IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
-
- switch (speed) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 38400:
- cflag |= B38400;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 9600:
- default:
- cflag |= B9600;
- break;
- }
-
- tty->termios->c_cflag = cflag;
- if (tty->driver->set_termios)
- tty->driver->set_termios(tty, &old_termios);
- unlock_kernel();
-
+ tty_encode_baud_rate(tty, speed, speed);
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old_termios);
priv->io.speed = speed;
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -202,8 +166,8 @@ static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
* This function is not yet defined for all tty driver, so
* let's be careful... Jean II
*/
- IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;);
- priv->tty->driver->tiocmset(priv->tty, NULL, set, clear);
+ IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;);
+ priv->tty->ops->tiocmset(priv->tty, NULL, set, clear);
return 0;
}
@@ -225,17 +189,13 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
tty = priv->tty;
- if (!tty->driver->write)
+ if (!tty->ops->write)
return 0;
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- if (tty->driver->write_room) {
- writelen = tty->driver->write_room(tty);
- if (writelen > len)
- writelen = len;
- }
- else
+ writelen = tty_write_room(tty);
+ if (writelen > len)
writelen = len;
- return tty->driver->write(tty, ptr, writelen);
+ return tty->ops->write(tty, ptr, writelen);
}
/* ------------------------------------------------------- */
@@ -321,7 +281,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
struct ktermios old_termios;
int cflag;
- lock_kernel();
+ mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
@@ -331,9 +291,9 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
cflag |= CREAD;
tty->termios->c_cflag = cflag;
- if (tty->driver->set_termios)
- tty->driver->set_termios(tty, &old_termios);
- unlock_kernel();
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old_termios);
+ mutex_unlock(&tty->termios_mutex);
}
/*****************************************************************/
@@ -359,8 +319,8 @@ static int irtty_start_dev(struct sir_dev *dev)
tty = priv->tty;
- if (tty->driver->start)
- tty->driver->start(tty);
+ if (tty->ops->start)
+ tty->ops->start(tty);
/* Make sure we can receive more data */
irtty_stop_receiver(tty, FALSE);
@@ -388,8 +348,8 @@ static int irtty_stop_dev(struct sir_dev *dev)
/* Make sure we don't receive more data */
irtty_stop_receiver(tty, TRUE);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
mutex_unlock(&irtty_mutex);
@@ -483,11 +443,10 @@ static int irtty_open(struct tty_struct *tty)
/* stop the underlying driver */
irtty_stop_receiver(tty, TRUE);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/* apply mtt override */
sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
@@ -564,8 +523,8 @@ static void irtty_close(struct tty_struct *tty)
/* Stop tty */
irtty_stop_receiver(tty, TRUE);
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
kfree(priv);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3ac8529bb92..6bf9e76b0a0 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -48,7 +48,7 @@ config VITESSE_PHY
config SMSC_PHY
tristate "Drivers for SMSC PHYs"
---help---
- Currently supports the LAN83C185 PHY
+ Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ddf8d51832a..ac3c01d28fd 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -256,7 +256,7 @@ void phy_prepare_link(struct phy_device *phydev,
/**
* phy_connect - connect an ethernet device to a PHY device
* @dev: the network device to connect
- * @phy_id: the PHY device to connect
+ * @bus_id: the id string of the PHY device to connect
* @handler: callback function for state change notifications
* @flags: PHY device's dev_flags
* @interface: PHY device's interface
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index b1d8ed40ad9..73baa7a3bb0 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -12,6 +12,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
+ * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@smsc.com
+ *
*/
#include <linux/kernel.h>
@@ -38,7 +40,7 @@
(MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
-static int lan83c185_config_intr(struct phy_device *phydev)
+static int smsc_phy_config_intr(struct phy_device *phydev)
{
int rc = phy_write (phydev, MII_LAN83C185_IM,
((PHY_INTERRUPT_ENABLED == phydev->interrupts)
@@ -48,16 +50,16 @@ static int lan83c185_config_intr(struct phy_device *phydev)
return rc < 0 ? rc : 0;
}
-static int lan83c185_ack_interrupt(struct phy_device *phydev)
+static int smsc_phy_ack_interrupt(struct phy_device *phydev)
{
int rc = phy_read (phydev, MII_LAN83C185_ISF);
return rc < 0 ? rc : 0;
}
-static int lan83c185_config_init(struct phy_device *phydev)
+static int smsc_phy_config_init(struct phy_device *phydev)
{
- return lan83c185_ack_interrupt (phydev);
+ return smsc_phy_ack_interrupt (phydev);
}
@@ -73,22 +75,87 @@ static struct phy_driver lan83c185_driver = {
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
- .config_init = lan83c185_config_init,
+ .config_init = smsc_phy_config_init,
/* IRQ related */
- .ack_interrupt = lan83c185_ack_interrupt,
- .config_intr = lan83c185_config_intr,
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8187_driver = {
+ .phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8187",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = smsc_phy_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8700_driver = {
+ .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8700",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = smsc_phy_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static int __init smsc_init(void)
{
- return phy_driver_register (&lan83c185_driver);
+ int ret;
+
+ ret = phy_driver_register (&lan83c185_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register (&lan8187_driver);
+ if (ret)
+ goto err2;
+
+ ret = phy_driver_register (&lan8700_driver);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ phy_driver_unregister (&lan8187_driver);
+err2:
+ phy_driver_unregister (&lan83c185_driver);
+err1:
+ return ret;
}
static void __exit smsc_exit(void)
{
+ phy_driver_unregister (&lan8700_driver);
+ phy_driver_unregister (&lan8187_driver);
phy_driver_unregister (&lan83c185_driver);
}
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index f023d5b67e6..f1a52def124 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -158,6 +158,9 @@ ppp_asynctty_open(struct tty_struct *tty)
struct asyncppp *ap;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
err = -ENOMEM;
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (!ap)
@@ -358,9 +361,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
ap_put(ap);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static void
@@ -676,7 +677,7 @@ ppp_async_push(struct asyncppp *ap)
if (!tty_stuffed && ap->optr < ap->olim) {
avail = ap->olim - ap->optr;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, ap->optr, avail);
+ sent = tty->ops->write(tty, ap->optr, avail);
if (sent < 0)
goto flush; /* error, e.g. loss of CD */
ap->optr += sent;
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 0d80fa54671..b8f0369a71e 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -207,6 +207,9 @@ ppp_sync_open(struct tty_struct *tty)
struct syncppp *ap;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
if (!ap)
@@ -398,9 +401,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
sp_put(ap);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static void
@@ -653,7 +654,7 @@ ppp_sync_push(struct syncppp *ap)
tty_stuffed = 0;
if (!tty_stuffed && ap->tpkt) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, ap->tpkt->data, ap->tpkt->len);
+ sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len);
if (sent < 0)
goto flush; /* error, e.g. loss of CD */
if (sent < ap->tpkt->len) {
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 3acfeeabdee..65724250462 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1617,6 +1617,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->dev = dev;
+ tp->pci_dev = pdev;
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
/* enable device (incl. PCI PM wakeup and hotplug setup) */
@@ -1705,18 +1706,18 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8169_print_mac_version(tp);
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
+ for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
if (tp->mac_version == rtl_chip_info[i].mac_version)
break;
}
- if (i < 0) {
+ if (i == ARRAY_SIZE(rtl_chip_info)) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
dev_printk(KERN_DEBUG, &pdev->dev,
"unknown chip version, assuming %s\n",
rtl_chip_info[0].name);
}
- i++;
+ i = 0;
}
tp->chipset = i;
@@ -1777,7 +1778,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
tp->intr_mask = 0xffff;
- tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
tp->align = cfg->align;
tp->hw_start = cfg->hw_start;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 157fd932e95..523478ebfd6 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -86,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.22"
+#define DRV_VERSION "2.0.26.23"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -809,6 +809,7 @@ static int init_shared_mem(struct s2io_nic *nic)
config->rx_cfg[i].num_rxd - 1;
mac_control->rings[i].nic = nic;
mac_control->rings[i].ring_no = i;
+ mac_control->rings[i].lro = lro_enable;
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode] + 1);
@@ -1560,113 +1561,112 @@ static int init_nic(struct s2io_nic *nic)
writeq(val64, &bar0->tx_fifo_partition_0);
/* Filling the Rx round robin registers as per the
- * number of Rings and steering based on QoS.
- */
+ * number of Rings and steering based on QoS with
+ * equal priority.
+ */
switch (config->rx_ring_num) {
case 1:
+ val64 = 0x0;
+ writeq(val64, &bar0->rx_w_round_robin_0);
+ writeq(val64, &bar0->rx_w_round_robin_1);
+ writeq(val64, &bar0->rx_w_round_robin_2);
+ writeq(val64, &bar0->rx_w_round_robin_3);
+ writeq(val64, &bar0->rx_w_round_robin_4);
+
val64 = 0x8080808080808080ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 2:
- val64 = 0x0000010000010000ULL;
+ val64 = 0x0001000100010001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0100000100000100ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0001000001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0000010000010000ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0100000000000000ULL;
+ val64 = 0x0001000100000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080808040404040ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 3:
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0001020000010001ULL;
+ val64 = 0x0200010200010200ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0200000100010200ULL;
+ val64 = 0x0102000102000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001020000000000ULL;
+ val64 = 0x0200010200000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080804040402020ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 4:
- val64 = 0x0001020300010200ULL;
+ val64 = 0x0001020300010203ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0100000102030001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0200010000010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0203000100000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201010ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 5:
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0001020304000102ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0304000102030400ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0102030400010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0400010203040001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001000000000000ULL;
+ val64 = 0x0203040000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201008ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 6:
- val64 = 0x0001020304000102ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0304050001020001ULL;
+ val64 = 0x0203040500010203ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0203000100000102ULL;
+ val64 = 0x0405000102030405ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304000102030405ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001000200000000ULL;
+ val64 = 0x0203040500000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020100804ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 7:
- val64 = 0x0001020001020300ULL;
+ val64 = 0x0001020304050600ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0102030400010203ULL;
+ val64 = 0x0102030405060001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0405060001020001ULL;
+ val64 = 0x0203040506000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304050000010200ULL;
+ val64 = 0x0304050600010203ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0102030000000000ULL;
+ val64 = 0x0405060000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080402010080402ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 8:
- val64 = 0x0001020300040105ULL;
+ val64 = 0x0001020304050607ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0200030106000204ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0103000502010007ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304010002060500ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0103020400000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8040201008040201ULL;
@@ -2499,8 +2499,7 @@ static void stop_nic(struct s2io_nic *nic)
/**
* fill_rx_buffers - Allocates the Rx side skbs
- * @nic: device private variable
- * @ring_no: ring number
+ * @ring_info: per ring structure
* Description:
* The function allocates Rx side skbs and puts the physical
* address of these buffers into the RxD buffer pointers, so that the NIC
@@ -2518,103 +2517,94 @@ static void stop_nic(struct s2io_nic *nic)
* SUCCESS on success or an appropriate -ve value on failure.
*/
-static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+static int fill_rx_buffers(struct ring_info *ring)
{
- struct net_device *dev = nic->dev;
struct sk_buff *skb;
struct RxD_t *rxdp;
- int off, off1, size, block_no, block_no1;
+ int off, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
- struct mac_info *mac_control;
- struct config_param *config;
u64 tmp;
struct buffAdd *ba;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
+ int rxd_index = 0;
struct RxD1 *rxdp1;
struct RxD3 *rxdp3;
- struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
+ struct swStat *stats = &ring->nic->mac_control.stats_info->sw_stat;
- mac_control = &nic->mac_control;
- config = &nic->config;
- alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
- atomic_read(&nic->rx_bufs_left[ring_no]);
+ alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left;
- block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
- off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
+ block_no1 = ring->rx_curr_get_info.block_index;
while (alloc_tab < alloc_cnt) {
- block_no = mac_control->rings[ring_no].rx_curr_put_info.
- block_index;
- off = mac_control->rings[ring_no].rx_curr_put_info.offset;
+ block_no = ring->rx_curr_put_info.block_index;
- rxdp = mac_control->rings[ring_no].
- rx_blocks[block_no].rxds[off].virt_addr;
+ off = ring->rx_curr_put_info.offset;
+
+ rxdp = ring->rx_blocks[block_no].rxds[off].virt_addr;
+
+ rxd_index = off + 1;
+ if (block_no)
+ rxd_index += (block_no * ring->rxd_count);
- if ((block_no == block_no1) && (off == off1) &&
- (rxdp->Host_Control)) {
+ if ((block_no == block_no1) &&
+ (off == ring->rx_curr_get_info.offset) &&
+ (rxdp->Host_Control)) {
DBG_PRINT(INTR_DBG, "%s: Get and Put",
- dev->name);
+ ring->dev->name);
DBG_PRINT(INTR_DBG, " info equated\n");
goto end;
}
- if (off && (off == rxd_count[nic->rxd_mode])) {
- mac_control->rings[ring_no].rx_curr_put_info.
- block_index++;
- if (mac_control->rings[ring_no].rx_curr_put_info.
- block_index == mac_control->rings[ring_no].
- block_count)
- mac_control->rings[ring_no].rx_curr_put_info.
- block_index = 0;
- block_no = mac_control->rings[ring_no].
- rx_curr_put_info.block_index;
- if (off == rxd_count[nic->rxd_mode])
- off = 0;
- mac_control->rings[ring_no].rx_curr_put_info.
- offset = off;
- rxdp = mac_control->rings[ring_no].
- rx_blocks[block_no].block_virt_addr;
+ if (off && (off == ring->rxd_count)) {
+ ring->rx_curr_put_info.block_index++;
+ if (ring->rx_curr_put_info.block_index ==
+ ring->block_count)
+ ring->rx_curr_put_info.block_index = 0;
+ block_no = ring->rx_curr_put_info.block_index;
+ off = 0;
+ ring->rx_curr_put_info.offset = off;
+ rxdp = ring->rx_blocks[block_no].block_virt_addr;
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
- dev->name, rxdp);
+ ring->dev->name, rxdp);
+
}
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
- ((nic->rxd_mode == RXD_MODE_3B) &&
+ ((ring->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & s2BIT(0)))) {
- mac_control->rings[ring_no].rx_curr_put_info.
- offset = off;
+ ring->rx_curr_put_info.offset = off;
goto end;
}
/* calculate size of skb based on ring mode */
- size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
+ size = ring->mtu + HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
- if (nic->rxd_mode == RXD_MODE_1)
+ if (ring->rxd_mode == RXD_MODE_1)
size += NET_IP_ALIGN;
else
- size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
+ size = ring->mtu + ALIGN_SIZE + BUF0_LEN + 4;
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
- DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name);
DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
- nic->mac_control.stats_info->sw_stat. \
- mem_alloc_fail_cnt++;
+ stats->mem_alloc_fail_cnt++;
+
return -ENOMEM ;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
- += skb->truesize;
- if (nic->rxd_mode == RXD_MODE_1) {
+ stats->mem_allocated += skb->truesize;
+
+ if (ring->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
rxdp1 = (struct RxD1*)rxdp;
memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
rxdp1->Buffer0_ptr = pci_map_single
- (nic->pdev, skb->data, size - NET_IP_ALIGN,
+ (ring->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
if( (rxdp1->Buffer0_ptr == 0) ||
(rxdp1->Buffer0_ptr ==
@@ -2623,8 +2613,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp->Control_2 =
SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
-
- } else if (nic->rxd_mode == RXD_MODE_3B) {
+ rxdp->Host_Control = (unsigned long) (skb);
+ } else if (ring->rxd_mode == RXD_MODE_3B) {
/*
* 2 buffer mode -
* 2 buffer mode provides 128
@@ -2640,7 +2630,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp3->Buffer0_ptr = Buffer0_ptr;
rxdp3->Buffer1_ptr = Buffer1_ptr;
- ba = &mac_control->rings[ring_no].ba[block_no][off];
+ ba = &ring->ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
tmp += ALIGN_SIZE;
@@ -2650,10 +2640,10 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
if (!(rxdp3->Buffer0_ptr))
rxdp3->Buffer0_ptr =
- pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
- PCI_DMA_FROMDEVICE);
+ pci_map_single(ring->pdev, ba->ba_0,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
else
- pci_dma_sync_single_for_device(nic->pdev,
+ pci_dma_sync_single_for_device(ring->pdev,
(dma_addr_t) rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer0_ptr == 0) ||
@@ -2661,7 +2651,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
goto pci_map_failed;
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
- if (nic->rxd_mode == RXD_MODE_3B) {
+ if (ring->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
/*
@@ -2669,39 +2659,42 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* L4 payload
*/
rxdp3->Buffer2_ptr = pci_map_single
- (nic->pdev, skb->data, dev->mtu + 4,
+ (ring->pdev, skb->data, ring->mtu + 4,
PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer2_ptr == 0) ||
(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
goto pci_map_failed;
- rxdp3->Buffer1_ptr =
- pci_map_single(nic->pdev,
+ if (!rxdp3->Buffer1_ptr)
+ rxdp3->Buffer1_ptr =
+ pci_map_single(ring->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
+
if( (rxdp3->Buffer1_ptr == 0) ||
(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
pci_unmap_single
- (nic->pdev,
- (dma_addr_t)rxdp3->Buffer2_ptr,
- dev->mtu + 4,
+ (ring->pdev,
+ (dma_addr_t)(unsigned long)
+ skb->data,
+ ring->mtu + 4,
PCI_DMA_FROMDEVICE);
goto pci_map_failed;
}
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
- (dev->mtu + 4);
+ (ring->mtu + 4);
}
rxdp->Control_2 |= s2BIT(0);
+ rxdp->Host_Control = (unsigned long) (skb);
}
- rxdp->Host_Control = (unsigned long) (skb);
if (alloc_tab & ((1 << rxsync_frequency) - 1))
rxdp->Control_1 |= RXD_OWN_XENA;
off++;
- if (off == (rxd_count[nic->rxd_mode] + 1))
+ if (off == (ring->rxd_count + 1))
off = 0;
- mac_control->rings[ring_no].rx_curr_put_info.offset = off;
+ ring->rx_curr_put_info.offset = off;
rxdp->Control_2 |= SET_RXD_MARKER;
if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
@@ -2711,7 +2704,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
first_rxdp = rxdp;
}
- atomic_inc(&nic->rx_bufs_left[ring_no]);
+ ring->rx_bufs_left += 1;
alloc_tab++;
}
@@ -2783,7 +2776,7 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
}
sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
dev_kfree_skb(skb);
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ mac_control->rings[ring_no].rx_bufs_left -= 1;
}
}
@@ -2814,7 +2807,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
mac_control->rings[i].rx_curr_get_info.block_index = 0;
mac_control->rings[i].rx_curr_put_info.offset = 0;
mac_control->rings[i].rx_curr_get_info.offset = 0;
- atomic_set(&sp->rx_bufs_left[i], 0);
+ mac_control->rings[i].rx_bufs_left = 0;
DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
dev->name, buf_cnt, i);
}
@@ -2864,7 +2857,7 @@ static int s2io_poll(struct napi_struct *napi, int budget)
netif_rx_complete(dev, napi);
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@@ -2877,7 +2870,7 @@ static int s2io_poll(struct napi_struct *napi, int budget)
no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@@ -2928,7 +2921,7 @@ static void s2io_netpoll(struct net_device *dev)
rx_intr_handler(&mac_control->rings[i]);
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
@@ -2953,8 +2946,6 @@ static void s2io_netpoll(struct net_device *dev)
*/
static void rx_intr_handler(struct ring_info *ring_data)
{
- struct s2io_nic *nic = ring_data->nic;
- struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
@@ -2977,33 +2968,34 @@ static void rx_intr_handler(struct ring_info *ring_data)
*/
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
- DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
+ DBG_PRINT(INTR_DBG, "%s: Ring Full\n",
+ ring_data->dev->name);
break;
}
skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: The skb is ",
- dev->name);
+ ring_data->dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
return;
}
- if (nic->rxd_mode == RXD_MODE_1) {
+ if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1*)rxdp;
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp1->Buffer0_ptr,
- dev->mtu +
+ ring_data->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
- } else if (nic->rxd_mode == RXD_MODE_3B) {
+ } else if (ring_data->rxd_mode == RXD_MODE_3B) {
rxdp3 = (struct RxD3*)rxdp;
- pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer2_ptr,
- dev->mtu + 4,
+ ring_data->mtu + 4,
PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@@ -3012,7 +3004,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
ring_data->rx_curr_get_info.offset = get_info.offset;
rxdp = ring_data->rx_blocks[get_block].
rxds[get_info.offset].virt_addr;
- if (get_info.offset == rxd_count[nic->rxd_mode]) {
+ if (get_info.offset == rxd_count[ring_data->rxd_mode]) {
get_info.offset = 0;
ring_data->rx_curr_get_info.offset = get_info.offset;
get_block++;
@@ -3022,19 +3014,21 @@ static void rx_intr_handler(struct ring_info *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
- nic->pkts_to_process -= 1;
- if ((napi) && (!nic->pkts_to_process))
- break;
+ if(ring_data->nic->config.napi){
+ ring_data->nic->pkts_to_process -= 1;
+ if (!ring_data->nic->pkts_to_process)
+ break;
+ }
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
}
- if (nic->lro) {
+ if (ring_data->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *lro = &nic->lro0_n[i];
+ struct lro *lro = &ring_data->lro0_n[i];
if (lro->in_use) {
- update_L3L4_header(nic, lro);
+ update_L3L4_header(ring_data->nic, lro);
queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro);
}
@@ -4333,10 +4327,10 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct ring_info *ring)
{
- if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ if (fill_rx_buffers(ring) == -ENOMEM) {
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
@@ -4351,7 +4345,7 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
return IRQ_HANDLED;
rx_intr_handler(ring);
- s2io_chk_rx_buffers(sp, ring->ring_no);
+ s2io_chk_rx_buffers(ring);
return IRQ_HANDLED;
}
@@ -4809,7 +4803,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
*/
if (!config->napi) {
for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
+ s2io_chk_rx_buffers(&mac_control->rings[i]);
}
writeq(sp->general_int_mask, &bar0->general_int_mask);
readl(&bar0->general_int_status);
@@ -4866,6 +4860,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
struct s2io_nic *sp = dev->priv;
struct mac_info *mac_control;
struct config_param *config;
+ int i;
mac_control = &sp->mac_control;
@@ -4885,6 +4880,13 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
sp->stats.rx_length_errors =
le64_to_cpu(mac_control->stats_info->rmac_long_frms);
+ /* collect per-ring rx_packets and rx_bytes */
+ sp->stats.rx_packets = sp->stats.rx_bytes = 0;
+ for (i = 0; i < config->rx_ring_num; i++) {
+ sp->stats.rx_packets += mac_control->rings[i].rx_packets;
+ sp->stats.rx_bytes += mac_control->rings[i].rx_bytes;
+ }
+
return (&sp->stats);
}
@@ -7157,7 +7159,9 @@ static int s2io_card_up(struct s2io_nic * sp)
config = &sp->config;
for (i = 0; i < config->rx_ring_num; i++) {
- if ((ret = fill_rx_buffers(sp, i))) {
+ mac_control->rings[i].mtu = dev->mtu;
+ ret = fill_rx_buffers(&mac_control->rings[i]);
+ if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
dev->name);
s2io_reset(sp);
@@ -7165,7 +7169,7 @@ static int s2io_card_up(struct s2io_nic * sp)
return -ENOMEM;
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
- atomic_read(&sp->rx_bufs_left[i]));
+ mac_control->rings[i].rx_bufs_left);
}
/* Initialise napi */
@@ -7300,7 +7304,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
struct s2io_nic *sp = ring_data->nic;
- struct net_device *dev = (struct net_device *) sp->dev;
+ struct net_device *dev = (struct net_device *) ring_data->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
@@ -7377,19 +7381,19 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
sp->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ ring_data->rx_bufs_left -= 1;
rxdp->Host_Control = 0;
return 0;
}
}
/* Updating statistics */
- sp->stats.rx_packets++;
+ ring_data->rx_packets++;
rxdp->Host_Control = 0;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
- sp->stats.rx_bytes += len;
+ ring_data->rx_bytes += len;
skb_put(skb, len);
} else if (sp->rxd_mode == RXD_MODE_3B) {
@@ -7400,13 +7404,13 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
unsigned char *buff = skb_push(skb, buf0_len);
struct buffAdd *ba = &ring_data->ba[get_block][get_off];
- sp->stats.rx_bytes += buf0_len + buf2_len;
+ ring_data->rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
skb_put(skb, buf2_len);
}
- if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
- (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
+ if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) ||
+ (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
(sp->rx_csum)) {
l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
@@ -7417,14 +7421,14 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
* a flag in the RxD.
*/
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (sp->lro) {
+ if (ring_data->lro) {
u32 tcp_len;
u8 *tcp;
int ret = 0;
- ret = s2io_club_tcp_session(skb->data, &tcp,
- &tcp_len, &lro,
- rxdp, sp);
+ ret = s2io_club_tcp_session(ring_data,
+ skb->data, &tcp, &tcp_len, &lro,
+ rxdp, sp);
switch (ret) {
case 3: /* Begin anew */
lro->parent = skb;
@@ -7486,7 +7490,7 @@ send_up:
queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
dev->last_rx = jiffies;
aggregate:
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ sp->mac_control.rings[ring_no].rx_bufs_left -= 1;
return SUCCESS;
}
@@ -7603,12 +7607,14 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
tx_steering_type = NO_STEERING;
}
- if ( rx_ring_num > 8) {
- DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
+ if (rx_ring_num > MAX_RX_RINGS) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested number of rx rings not "
"supported\n");
- DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
- rx_ring_num = 8;
+ DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n",
+ MAX_RX_RINGS);
+ rx_ring_num = MAX_RX_RINGS;
}
+
if (*dev_intr_type != INTA)
napi = 0;
@@ -7836,10 +7842,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Rx side parameters. */
config->rx_ring_num = rx_ring_num;
- for (i = 0; i < MAX_RX_RINGS; i++) {
+ for (i = 0; i < config->rx_ring_num; i++) {
config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
(rxd_count[sp->rxd_mode] + 1);
config->rx_cfg[i].ring_priority = i;
+ mac_control->rings[i].rx_bufs_left = 0;
+ mac_control->rings[i].rxd_mode = sp->rxd_mode;
+ mac_control->rings[i].rxd_count = rxd_count[sp->rxd_mode];
+ mac_control->rings[i].pdev = sp->pdev;
+ mac_control->rings[i].dev = sp->dev;
}
for (i = 0; i < rx_ring_num; i++) {
@@ -7854,10 +7865,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
- /* Initialize Ring buffer parameters. */
- for (i = 0; i < config->rx_ring_num; i++)
- atomic_set(&sp->rx_bufs_left[i], 0);
-
/* initialize the shared memory used by the NIC and the host */
if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
@@ -8077,6 +8084,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num);
+ DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name,
+ sp->config.rx_ring_num);
+
switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -8391,8 +8401,9 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
}
static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
- struct RxD_t *rxdp, struct s2io_nic *sp)
+s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp,
+ u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
+ struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@@ -8410,7 +8421,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &ring_data->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@@ -8448,7 +8459,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &ring_data->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index ce53a02105f..0709ebae913 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -678,11 +678,53 @@ struct rx_block_info {
struct rxd_info *rxds;
};
+/* Data structure to represent a LRO session */
+struct lro {
+ struct sk_buff *parent;
+ struct sk_buff *last_frag;
+ u8 *l2h;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ u32 tcp_next_seq;
+ __be32 tcp_ack;
+ int total_len;
+ int frags_len;
+ int sg_num;
+ int in_use;
+ __be16 window;
+ u16 vlan_tag;
+ u32 cur_tsval;
+ __be32 cur_tsecr;
+ u8 saw_ts;
+} ____cacheline_aligned;
+
/* Ring specific structure */
struct ring_info {
/* The ring number */
int ring_no;
+ /* per-ring buffer counter */
+ u32 rx_bufs_left;
+
+ #define MAX_LRO_SESSIONS 32
+ struct lro lro0_n[MAX_LRO_SESSIONS];
+ u8 lro;
+
+ /* copy of sp->rxd_mode flag */
+ int rxd_mode;
+
+ /* Number of rxds per block for the rxd_mode */
+ int rxd_count;
+
+ /* copy of sp pointer */
+ struct s2io_nic *nic;
+
+ /* copy of sp->dev pointer */
+ struct net_device *dev;
+
+ /* copy of sp->pdev pointer */
+ struct pci_dev *pdev;
+
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
@@ -703,10 +745,16 @@ struct ring_info {
*/
struct rx_curr_get_info rx_curr_get_info;
+ /* interface MTU value */
+ unsigned mtu;
+
/* Buffer Address store. */
struct buffAdd **ba;
- struct s2io_nic *nic;
-};
+
+ /* per-Ring statistics */
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+} ____cacheline_aligned;
/* Fifo specific structure */
struct fifo_info {
@@ -813,26 +861,6 @@ struct msix_info_st {
u64 data;
};
-/* Data structure to represent a LRO session */
-struct lro {
- struct sk_buff *parent;
- struct sk_buff *last_frag;
- u8 *l2h;
- struct iphdr *iph;
- struct tcphdr *tcph;
- u32 tcp_next_seq;
- __be32 tcp_ack;
- int total_len;
- int frags_len;
- int sg_num;
- int in_use;
- __be16 window;
- u16 vlan_tag;
- u32 cur_tsval;
- __be32 cur_tsecr;
- u8 saw_ts;
-} ____cacheline_aligned;
-
/* These flags represent the devices temporary state */
enum s2io_device_state_t
{
@@ -872,8 +900,6 @@ struct s2io_nic {
/* Space to back up the PCI config space */
u32 config_space[256 / sizeof(u32)];
- atomic_t rx_bufs_left[MAX_RX_RINGS];
-
#define PROMISC 1
#define ALL_MULTI 2
@@ -950,8 +976,6 @@ struct s2io_nic {
#define XFRAME_II_DEVICE 2
u8 device_type;
-#define MAX_LRO_SESSIONS 32
- struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@@ -1118,9 +1142,9 @@ static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr);
static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int offset);
static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr);
-static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
- struct RxD_t *rxdp, struct s2io_nic *sp);
+static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer,
+ u8 **tcp, u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
+ struct s2io_nic *sp);
static void clear_lro_session(struct lro *lro);
static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag);
static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig
new file mode 100644
index 00000000000..dbad95c295b
--- /dev/null
+++ b/drivers/net/sfc/Kconfig
@@ -0,0 +1,12 @@
+config SFC
+ tristate "Solarflare Solarstorm SFC4000 support"
+ depends on PCI && INET
+ select MII
+ select INET_LRO
+ select CRC32
+ help
+ This driver supports 10-gigabit Ethernet cards based on
+ the Solarflare Communications Solarstorm SFC4000 controller.
+
+ To compile this driver as a module, choose M here. The module
+ will be called sfc.
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
new file mode 100644
index 00000000000..0f023447eaf
--- /dev/null
+++ b/drivers/net/sfc/Makefile
@@ -0,0 +1,5 @@
+sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
+ i2c-direct.o ethtool.o xfp_phy.o mdio_10g.o \
+ tenxpress.o boards.o sfe4001.o
+
+obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h
new file mode 100644
index 00000000000..2806201644c
--- /dev/null
+++ b/drivers/net/sfc/bitfield.h
@@ -0,0 +1,508 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_BITFIELD_H
+#define EFX_BITFIELD_H
+
+/*
+ * Efx bitfield access
+ *
+ * Efx NICs make extensive use of bitfields up to 128 bits
+ * wide. Since there is no native 128-bit datatype on most systems,
+ * and since 64-bit datatypes are inefficient on 32-bit systems and
+ * vice versa, we wrap accesses in a way that uses the most efficient
+ * datatype.
+ *
+ * The NICs are PCI devices and therefore little-endian. Since most
+ * of the quantities that we deal with are DMAed to/from host memory,
+ * we define our datatypes (efx_oword_t, efx_qword_t and
+ * efx_dword_t) to be little-endian.
+ */
+
+/* Lowest bit numbers and widths */
+#define EFX_DUMMY_FIELD_LBN 0
+#define EFX_DUMMY_FIELD_WIDTH 0
+#define EFX_DWORD_0_LBN 0
+#define EFX_DWORD_0_WIDTH 32
+#define EFX_DWORD_1_LBN 32
+#define EFX_DWORD_1_WIDTH 32
+#define EFX_DWORD_2_LBN 64
+#define EFX_DWORD_2_WIDTH 32
+#define EFX_DWORD_3_LBN 96
+#define EFX_DWORD_3_WIDTH 32
+
+/* Specified attribute (e.g. LBN) of the specified field */
+#define EFX_VAL(field, attribute) field ## _ ## attribute
+/* Low bit number of the specified field */
+#define EFX_LOW_BIT(field) EFX_VAL(field, LBN)
+/* Bit width of the specified field */
+#define EFX_WIDTH(field) EFX_VAL(field, WIDTH)
+/* High bit number of the specified field */
+#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1)
+/* Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 64 bits.
+ */
+#define EFX_MASK64(field) \
+ (EFX_WIDTH(field) == 64 ? ~((u64) 0) : \
+ (((((u64) 1) << EFX_WIDTH(field))) - 1))
+
+/* Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 32 bits. Use
+ * EFX_MASK64 for higher width fields.
+ */
+#define EFX_MASK32(field) \
+ (EFX_WIDTH(field) == 32 ? ~((u32) 0) : \
+ (((((u32) 1) << EFX_WIDTH(field))) - 1))
+
+/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
+typedef union efx_dword {
+ __le32 u32[1];
+} efx_dword_t;
+
+/* A quadword (i.e. 8 byte) datatype - little-endian in HW */
+typedef union efx_qword {
+ __le64 u64[1];
+ __le32 u32[2];
+ efx_dword_t dword[2];
+} efx_qword_t;
+
+/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */
+typedef union efx_oword {
+ __le64 u64[2];
+ efx_qword_t qword[2];
+ __le32 u32[4];
+ efx_dword_t dword[4];
+} efx_oword_t;
+
+/* Format string and value expanders for printk */
+#define EFX_DWORD_FMT "%08x"
+#define EFX_QWORD_FMT "%08x:%08x"
+#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x"
+#define EFX_DWORD_VAL(dword) \
+ ((unsigned int) le32_to_cpu((dword).u32[0]))
+#define EFX_QWORD_VAL(qword) \
+ ((unsigned int) le32_to_cpu((qword).u32[1])), \
+ ((unsigned int) le32_to_cpu((qword).u32[0]))
+#define EFX_OWORD_VAL(oword) \
+ ((unsigned int) le32_to_cpu((oword).u32[3])), \
+ ((unsigned int) le32_to_cpu((oword).u32[2])), \
+ ((unsigned int) le32_to_cpu((oword).u32[1])), \
+ ((unsigned int) le32_to_cpu((oword).u32[0]))
+
+/*
+ * Extract bit field portion [low,high) from the native-endian element
+ * which contains bits [min,max).
+ *
+ * For example, suppose "element" represents the high 32 bits of a
+ * 64-bit value, and we wish to extract the bits belonging to the bit
+ * field occupying bits 28-45 of this 64-bit value.
+ *
+ * Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give
+ *
+ * ( element ) << 4
+ *
+ * The result will contain the relevant bits filled in in the range
+ * [0,high-low), with garbage in bits [high-low+1,...).
+ */
+#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ ((native_element) >> (low - min)) : \
+ ((native_element) << (min - low))))
+
+/*
+ * Extract bit field portion [low,high) from the 64-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFX_EXTRACT64(element, min, max, low, high) \
+ EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high)
+
+/*
+ * Extract bit field portion [low,high) from the 32-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFX_EXTRACT32(element, min, max, low, high) \
+ EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
+
+#define EFX_EXTRACT_OWORD64(oword, low, high) \
+ (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \
+ EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
+
+#define EFX_EXTRACT_QWORD64(qword, low, high) \
+ EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
+
+#define EFX_EXTRACT_OWORD32(oword, low, high) \
+ (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \
+ EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \
+ EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \
+ EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
+
+#define EFX_EXTRACT_QWORD32(qword, low, high) \
+ (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \
+ EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
+
+#define EFX_EXTRACT_DWORD(dword, low, high) \
+ EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
+
+#define EFX_OWORD_FIELD64(oword, field) \
+ (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK64(field))
+
+#define EFX_QWORD_FIELD64(qword, field) \
+ (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK64(field))
+
+#define EFX_OWORD_FIELD32(oword, field) \
+ (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_QWORD_FIELD32(qword, field) \
+ (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_DWORD_FIELD(dword, field) \
+ (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_OWORD_IS_ZERO64(oword) \
+ (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
+
+#define EFX_QWORD_IS_ZERO64(qword) \
+ (((qword).u64[0]) == (__force __le64) 0)
+
+#define EFX_OWORD_IS_ZERO32(oword) \
+ (((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \
+ == (__force __le32) 0)
+
+#define EFX_QWORD_IS_ZERO32(qword) \
+ (((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0)
+
+#define EFX_DWORD_IS_ZERO(dword) \
+ (((dword).u32[0]) == (__force __le32) 0)
+
+#define EFX_OWORD_IS_ALL_ONES64(oword) \
+ (((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0))
+
+#define EFX_QWORD_IS_ALL_ONES64(qword) \
+ ((qword).u64[0] == ~((__force __le64) 0))
+
+#define EFX_OWORD_IS_ALL_ONES32(oword) \
+ (((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \
+ == ~((__force __le32) 0))
+
+#define EFX_QWORD_IS_ALL_ONES32(qword) \
+ (((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0))
+
+#define EFX_DWORD_IS_ALL_ONES(dword) \
+ ((dword).u32[0] == ~((__force __le32) 0))
+
+#if BITS_PER_LONG == 64
+#define EFX_OWORD_FIELD EFX_OWORD_FIELD64
+#define EFX_QWORD_FIELD EFX_QWORD_FIELD64
+#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO64
+#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO64
+#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64
+#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64
+#else
+#define EFX_OWORD_FIELD EFX_OWORD_FIELD32
+#define EFX_QWORD_FIELD EFX_QWORD_FIELD32
+#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO32
+#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO32
+#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32
+#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32
+#endif
+
+/*
+ * Construct bit field portion
+ *
+ * Creates the portion of the bit field [low,high) that lies within
+ * the range [min,max).
+ */
+#define EFX_INSERT_NATIVE64(min, max, low, high, value) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ (((u64) (value)) << (low - min)) : \
+ (((u64) (value)) >> (min - low))))
+
+#define EFX_INSERT_NATIVE32(min, max, low, high, value) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ (((u32) (value)) << (low - min)) : \
+ (((u32) (value)) >> (min - low))))
+
+#define EFX_INSERT_NATIVE(min, max, low, high, value) \
+ ((((max - min) >= 32) || ((high - low) >= 32)) ? \
+ EFX_INSERT_NATIVE64(min, max, low, high, value) : \
+ EFX_INSERT_NATIVE32(min, max, low, high, value))
+
+/*
+ * Construct bit field portion
+ *
+ * Creates the portion of the named bit field that lies within the
+ * range [min,max).
+ */
+#define EFX_INSERT_FIELD_NATIVE(min, max, field, value) \
+ EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field), \
+ EFX_HIGH_BIT(field), value)
+
+/*
+ * Construct bit field
+ *
+ * Creates the portion of the named bit fields that lie within the
+ * range [min,max).
+ */
+#define EFX_INSERT_FIELDS_NATIVE(min, max, \
+ field1, value1, \
+ field2, value2, \
+ field3, value3, \
+ field4, value4, \
+ field5, value5, \
+ field6, value6, \
+ field7, value7, \
+ field8, value8, \
+ field9, value9, \
+ field10, value10) \
+ (EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)))
+
+#define EFX_INSERT_FIELDS64(...) \
+ cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
+
+#define EFX_INSERT_FIELDS32(...) \
+ cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
+
+#define EFX_POPULATE_OWORD64(oword, ...) do { \
+ (oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
+ (oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_QWORD64(qword, ...) do { \
+ (qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_OWORD32(oword, ...) do { \
+ (oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ (oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
+ (oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__); \
+ (oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_QWORD32(qword, ...) do { \
+ (qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ (qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_DWORD(dword, ...) do { \
+ (dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ } while (0)
+
+#if BITS_PER_LONG == 64
+#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
+#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
+#else
+#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
+#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
+#endif
+
+/* Populate an octword field with various numbers of arguments */
+#define EFX_POPULATE_OWORD_10 EFX_POPULATE_OWORD
+#define EFX_POPULATE_OWORD_9(oword, ...) \
+ EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_8(oword, ...) \
+ EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_7(oword, ...) \
+ EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_6(oword, ...) \
+ EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_5(oword, ...) \
+ EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_4(oword, ...) \
+ EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_3(oword, ...) \
+ EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_2(oword, ...) \
+ EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_1(oword, ...) \
+ EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_OWORD(oword) \
+ EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_OWORD(oword) \
+ EFX_POPULATE_OWORD_4(oword, \
+ EFX_DWORD_0, 0xffffffff, \
+ EFX_DWORD_1, 0xffffffff, \
+ EFX_DWORD_2, 0xffffffff, \
+ EFX_DWORD_3, 0xffffffff)
+
+/* Populate a quadword field with various numbers of arguments */
+#define EFX_POPULATE_QWORD_10 EFX_POPULATE_QWORD
+#define EFX_POPULATE_QWORD_9(qword, ...) \
+ EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_8(qword, ...) \
+ EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_7(qword, ...) \
+ EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_6(qword, ...) \
+ EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_5(qword, ...) \
+ EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_4(qword, ...) \
+ EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_3(qword, ...) \
+ EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_2(qword, ...) \
+ EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_1(qword, ...) \
+ EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_QWORD(qword) \
+ EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_QWORD(qword) \
+ EFX_POPULATE_QWORD_2(qword, \
+ EFX_DWORD_0, 0xffffffff, \
+ EFX_DWORD_1, 0xffffffff)
+
+/* Populate a dword field with various numbers of arguments */
+#define EFX_POPULATE_DWORD_10 EFX_POPULATE_DWORD
+#define EFX_POPULATE_DWORD_9(dword, ...) \
+ EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_8(dword, ...) \
+ EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_7(dword, ...) \
+ EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_6(dword, ...) \
+ EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_5(dword, ...) \
+ EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_4(dword, ...) \
+ EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_3(dword, ...) \
+ EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_2(dword, ...) \
+ EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_1(dword, ...) \
+ EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_DWORD(dword) \
+ EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_DWORD(dword) \
+ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff)
+
+/*
+ * Modify a named field within an already-populated structure. Used
+ * for read-modify-write operations.
+ *
+ */
+
+#define EFX_INVERT_OWORD(oword) do { \
+ (oword).u64[0] = ~((oword).u64[0]); \
+ (oword).u64[1] = ~((oword).u64[1]); \
+ } while (0)
+
+#define EFX_INSERT_FIELD64(...) \
+ cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+
+#define EFX_INSERT_FIELD32(...) \
+ cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+
+#define EFX_INPLACE_MASK64(min, max, field) \
+ EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
+
+#define EFX_INPLACE_MASK32(min, max, field) \
+ EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
+
+#define EFX_SET_OWORD_FIELD64(oword, field, value) do { \
+ (oword).u64[0] = (((oword).u64[0] \
+ & ~EFX_INPLACE_MASK64(0, 63, field)) \
+ | EFX_INSERT_FIELD64(0, 63, field, value)); \
+ (oword).u64[1] = (((oword).u64[1] \
+ & ~EFX_INPLACE_MASK64(64, 127, field)) \
+ | EFX_INSERT_FIELD64(64, 127, field, value)); \
+ } while (0)
+
+#define EFX_SET_QWORD_FIELD64(qword, field, value) do { \
+ (qword).u64[0] = (((qword).u64[0] \
+ & ~EFX_INPLACE_MASK64(0, 63, field)) \
+ | EFX_INSERT_FIELD64(0, 63, field, value)); \
+ } while (0)
+
+#define EFX_SET_OWORD_FIELD32(oword, field, value) do { \
+ (oword).u32[0] = (((oword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ (oword).u32[1] = (((oword).u32[1] \
+ & ~EFX_INPLACE_MASK32(32, 63, field)) \
+ | EFX_INSERT_FIELD32(32, 63, field, value)); \
+ (oword).u32[2] = (((oword).u32[2] \
+ & ~EFX_INPLACE_MASK32(64, 95, field)) \
+ | EFX_INSERT_FIELD32(64, 95, field, value)); \
+ (oword).u32[3] = (((oword).u32[3] \
+ & ~EFX_INPLACE_MASK32(96, 127, field)) \
+ | EFX_INSERT_FIELD32(96, 127, field, value)); \
+ } while (0)
+
+#define EFX_SET_QWORD_FIELD32(qword, field, value) do { \
+ (qword).u32[0] = (((qword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ (qword).u32[1] = (((qword).u32[1] \
+ & ~EFX_INPLACE_MASK32(32, 63, field)) \
+ | EFX_INSERT_FIELD32(32, 63, field, value)); \
+ } while (0)
+
+#define EFX_SET_DWORD_FIELD(dword, field, value) do { \
+ (dword).u32[0] = (((dword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ } while (0)
+
+#if BITS_PER_LONG == 64
+#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
+#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
+#else
+#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
+#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
+#endif
+
+#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
+ if (FALCON_REV(efx) >= FALCON_REV_B0) { \
+ EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
+ } else { \
+ EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
+ } \
+} while (0)
+
+#define EFX_QWORD_FIELD_VER(efx, qword, field) \
+ (FALCON_REV(efx) >= FALCON_REV_B0 ? \
+ EFX_QWORD_FIELD((qword), field##_B0) : \
+ EFX_QWORD_FIELD((qword), field##_A1))
+
+/* Used to avoid compiler warnings about shift range exceeding width
+ * of the data types when dma_addr_t is only 32 bits wide.
+ */
+#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t))
+#define EFX_DMA_TYPE_WIDTH(width) \
+ (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
+#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
+ ~((u64) 0) : ~((u32) 0))
+#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
+
+#endif /* EFX_BITFIELD_H */
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
new file mode 100644
index 00000000000..eecaa6d5858
--- /dev/null
+++ b/drivers/net/sfc/boards.c
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include "net_driver.h"
+#include "phy.h"
+#include "boards.h"
+#include "efx.h"
+
+/* Macros for unpacking the board revision */
+/* The revision info is in host byte order. */
+#define BOARD_TYPE(_rev) (_rev >> 8)
+#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
+#define BOARD_MINOR(_rev) (_rev & 0xf)
+
+/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
+#define BLINK_INTERVAL (HZ/2)
+
+static void blink_led_timer(unsigned long context)
+{
+ struct efx_nic *efx = (struct efx_nic *)context;
+ struct efx_blinker *bl = &efx->board_info.blinker;
+ efx->board_info.set_fault_led(efx, bl->state);
+ bl->state = !bl->state;
+ if (bl->resubmit) {
+ bl->timer.expires = jiffies + BLINK_INTERVAL;
+ add_timer(&bl->timer);
+ }
+}
+
+static void board_blink(struct efx_nic *efx, int blink)
+{
+ struct efx_blinker *blinker = &efx->board_info.blinker;
+
+ /* The rtnl mutex serialises all ethtool ioctls, so
+ * nothing special needs doing here. */
+ if (blink) {
+ blinker->resubmit = 1;
+ blinker->state = 0;
+ setup_timer(&blinker->timer, blink_led_timer,
+ (unsigned long)efx);
+ blinker->timer.expires = jiffies + BLINK_INTERVAL;
+ add_timer(&blinker->timer);
+ } else {
+ blinker->resubmit = 0;
+ if (blinker->timer.function)
+ del_timer_sync(&blinker->timer);
+ efx->board_info.set_fault_led(efx, 0);
+ }
+}
+
+/*****************************************************************************
+ * Support for the SFE4002
+ *
+ */
+/****************************************************************************/
+/* LED allocations. Note that on rev A0 boards the schematic and the reality
+ * differ: red and green are swapped. Below is the fixed (A1) layout (there
+ * are only 3 A0 boards in existence, so no real reason to make this
+ * conditional).
+ */
+#define SFE4002_FAULT_LED (2) /* Red */
+#define SFE4002_RX_LED (0) /* Green */
+#define SFE4002_TX_LED (1) /* Amber */
+
+static int sfe4002_init_leds(struct efx_nic *efx)
+{
+ /* Set the TX and RX LEDs to reflect status and activity, and the
+ * fault LED off */
+ xfp_set_led(efx, SFE4002_TX_LED,
+ QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
+ xfp_set_led(efx, SFE4002_RX_LED,
+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
+ xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
+ efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
+ return 0;
+}
+
+static void sfe4002_fault_led(struct efx_nic *efx, int state)
+{
+ xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
+ QUAKE_LED_OFF);
+}
+
+static int sfe4002_init(struct efx_nic *efx)
+{
+ efx->board_info.init_leds = sfe4002_init_leds;
+ efx->board_info.set_fault_led = sfe4002_fault_led;
+ efx->board_info.blink = board_blink;
+ return 0;
+}
+
+/* This will get expanded as board-specific details get moved out of the
+ * PHY drivers. */
+struct efx_board_data {
+ const char *ref_model;
+ const char *gen_type;
+ int (*init) (struct efx_nic *nic);
+};
+
+static int dummy_init(struct efx_nic *nic)
+{
+ return 0;
+}
+
+static struct efx_board_data board_data[] = {
+ [EFX_BOARD_INVALID] =
+ {NULL, NULL, dummy_init},
+ [EFX_BOARD_SFE4001] =
+ {"SFE4001", "10GBASE-T adapter", sfe4001_poweron},
+ [EFX_BOARD_SFE4002] =
+ {"SFE4002", "XFP adapter", sfe4002_init},
+};
+
+int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
+{
+ int rc = 0;
+ struct efx_board_data *data;
+
+ if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
+ EFX_ERR(efx, "squashing unknown board type %d\n",
+ BOARD_TYPE(revision_info));
+ revision_info = 0;
+ }
+
+ if (BOARD_TYPE(revision_info) == 0) {
+ efx->board_info.major = 0;
+ efx->board_info.minor = 0;
+ /* For early boards that don't have revision info. there is
+ * only 1 board for each PHY type, so we can work it out, with
+ * the exception of the PHY-less boards. */
+ switch (efx->phy_type) {
+ case PHY_TYPE_10XPRESS:
+ efx->board_info.type = EFX_BOARD_SFE4001;
+ break;
+ case PHY_TYPE_XFP:
+ efx->board_info.type = EFX_BOARD_SFE4002;
+ break;
+ default:
+ efx->board_info.type = 0;
+ break;
+ }
+ } else {
+ efx->board_info.type = BOARD_TYPE(revision_info);
+ efx->board_info.major = BOARD_MAJOR(revision_info);
+ efx->board_info.minor = BOARD_MINOR(revision_info);
+ }
+
+ data = &board_data[efx->board_info.type];
+
+ /* Report the board model number or generic type for recognisable
+ * boards. */
+ if (efx->board_info.type != 0)
+ EFX_INFO(efx, "board is %s rev %c%d\n",
+ (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
+ ? data->ref_model : data->gen_type,
+ 'A' + efx->board_info.major, efx->board_info.minor);
+
+ efx->board_info.init = data->init;
+
+ return rc;
+}
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
new file mode 100644
index 00000000000..f56341d428e
--- /dev/null
+++ b/drivers/net/sfc/boards.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_BOARDS_H
+#define EFX_BOARDS_H
+
+/* Board IDs (must fit in 8 bits) */
+enum efx_board_type {
+ EFX_BOARD_INVALID = 0,
+ EFX_BOARD_SFE4001 = 1, /* SFE4001 (10GBASE-T) */
+ EFX_BOARD_SFE4002 = 2,
+ /* Insert new types before here */
+ EFX_BOARD_MAX
+};
+
+extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
+extern int sfe4001_poweron(struct efx_nic *efx);
+extern void sfe4001_poweroff(struct efx_nic *efx);
+
+#endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
new file mode 100644
index 00000000000..59edcf793c1
--- /dev/null
+++ b/drivers/net/sfc/efx.c
@@ -0,0 +1,2208 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include "net_driver.h"
+#include "gmii.h"
+#include "ethtool.h"
+#include "tx.h"
+#include "rx.h"
+#include "efx.h"
+#include "mdio_10g.h"
+#include "falcon.h"
+#include "workarounds.h"
+#include "mac.h"
+
+#define EFX_MAX_MTU (9 * 1024)
+
+/* RX slow fill workqueue. If memory allocation fails in the fast path,
+ * a work item is pushed onto this work queue to retry the allocation later,
+ * to avoid the NIC being starved of RX buffers. Since this is a per cpu
+ * workqueue, there is nothing to be gained in making it per NIC
+ */
+static struct workqueue_struct *refill_workqueue;
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ *************************************************************************/
+
+/*
+ * Enable large receive offload (LRO) aka soft segment reassembly (SSR)
+ *
+ * This sets the default for new devices. It can be controlled later
+ * using ethtool.
+ */
+static int lro = 1;
+module_param(lro, int, 0644);
+MODULE_PARM_DESC(lro, "Large receive offload acceleration");
+
+/*
+ * Use separate channels for TX and RX events
+ *
+ * Set this to 1 to use separate channels for TX and RX. It allows us to
+ * apply a higher level of interrupt moderation to TX events.
+ *
+ * This is forced to 0 for MSI interrupt mode as the interrupt vector
+ * is not written
+ */
+static unsigned int separate_tx_and_rx_channels = 1;
+
+/* This is the weight assigned to each of the (per-channel) virtual
+ * NAPI devices.
+ */
+static int napi_weight = 64;
+
+/* This is the time (in jiffies) between invocations of the hardware
+ * monitor, which checks for known hardware bugs and resets the
+ * hardware and driver as necessary.
+ */
+unsigned int efx_monitor_interval = 1 * HZ;
+
+/* This controls whether or not the hardware monitor will trigger a
+ * reset when it detects an error condition.
+ */
+static unsigned int monitor_reset = 1;
+
+/* This controls whether or not the driver will initialise devices
+ * with invalid MAC addresses stored in the EEPROM or flash. If true,
+ * such devices will be initialised with a random locally-generated
+ * MAC address. This allows for loading the sfc_mtd driver to
+ * reprogram the flash, even if the flash contents (including the MAC
+ * address) have previously been erased.
+ */
+static unsigned int allow_bad_hwaddr;
+
+/* Initial interrupt moderation settings. They can be modified after
+ * module load with ethtool.
+ *
+ * The default for RX should strike a balance between increasing the
+ * round-trip latency and reducing overhead.
+ */
+static unsigned int rx_irq_mod_usec = 60;
+
+/* Initial interrupt moderation settings. They can be modified after
+ * module load with ethtool.
+ *
+ * This default is chosen to ensure that a 10G link does not go idle
+ * while a TX queue is stopped after it has become full. A queue is
+ * restarted when it drops below half full. The time this takes (assuming
+ * worst case 3 descriptors per packet and 1024 descriptors) is
+ * 512 / 3 * 1.2 = 205 usec.
+ */
+static unsigned int tx_irq_mod_usec = 150;
+
+/* This is the first interrupt mode to try out of:
+ * 0 => MSI-X
+ * 1 => MSI
+ * 2 => legacy
+ */
+static unsigned int interrupt_mode;
+
+/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
+ * i.e. the number of CPUs among which we may distribute simultaneous
+ * interrupt handling.
+ *
+ * Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
+ * The default (0) means to assign an interrupt to each package (level II cache)
+ */
+static unsigned int rss_cpus;
+module_param(rss_cpus, uint, 0444);
+MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
+
+/**************************************************************************
+ *
+ * Utility functions and prototypes
+ *
+ *************************************************************************/
+static void efx_remove_channel(struct efx_channel *channel);
+static void efx_remove_port(struct efx_nic *efx);
+static void efx_fini_napi(struct efx_nic *efx);
+static void efx_fini_channels(struct efx_nic *efx);
+
+#define EFX_ASSERT_RESET_SERIALISED(efx) \
+ do { \
+ if ((efx->state == STATE_RUNNING) || \
+ (efx->state == STATE_RESETTING)) \
+ ASSERT_RTNL(); \
+ } while (0)
+
+/**************************************************************************
+ *
+ * Event queue processing
+ *
+ *************************************************************************/
+
+/* Process channel's event queue
+ *
+ * This function is responsible for processing the event queue of a
+ * single channel. The caller must guarantee that this function will
+ * never be concurrently called more than once on the same channel,
+ * though different channels may be being processed concurrently.
+ */
+static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
+{
+ int rxdmaqs;
+ struct efx_rx_queue *rx_queue;
+
+ if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
+ !channel->enabled))
+ return rx_quota;
+
+ rxdmaqs = falcon_process_eventq(channel, &rx_quota);
+
+ /* Deliver last RX packet. */
+ if (channel->rx_pkt) {
+ __efx_rx_packet(channel, channel->rx_pkt,
+ channel->rx_pkt_csummed);
+ channel->rx_pkt = NULL;
+ }
+
+ efx_flush_lro(channel);
+ efx_rx_strategy(channel);
+
+ /* Refill descriptor rings as necessary */
+ rx_queue = &channel->efx->rx_queue[0];
+ while (rxdmaqs) {
+ if (rxdmaqs & 0x01)
+ efx_fast_push_rx_descriptors(rx_queue);
+ rx_queue++;
+ rxdmaqs >>= 1;
+ }
+
+ return rx_quota;
+}
+
+/* Mark channel as finished processing
+ *
+ * Note that since we will not receive further interrupts for this
+ * channel before we finish processing and call the eventq_read_ack()
+ * method, there is no need to use the interrupt hold-off timers.
+ */
+static inline void efx_channel_processed(struct efx_channel *channel)
+{
+ /* Write to EVQ_RPTR_REG. If a new event arrived in a race
+ * with finishing processing, a new interrupt will be raised.
+ */
+ channel->work_pending = 0;
+ smp_wmb(); /* Ensure channel updated before any new interrupt. */
+ falcon_eventq_read_ack(channel);
+}
+
+/* NAPI poll handler
+ *
+ * NAPI guarantees serialisation of polls of the same device, which
+ * provides the guarantee required by efx_process_channel().
+ */
+static int efx_poll(struct napi_struct *napi, int budget)
+{
+ struct efx_channel *channel =
+ container_of(napi, struct efx_channel, napi_str);
+ struct net_device *napi_dev = channel->napi_dev;
+ int unused;
+ int rx_packets;
+
+ EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
+ channel->channel, raw_smp_processor_id());
+
+ unused = efx_process_channel(channel, budget);
+ rx_packets = (budget - unused);
+
+ if (rx_packets < budget) {
+ /* There is no race here; although napi_disable() will
+ * only wait for netif_rx_complete(), this isn't a problem
+ * since efx_channel_processed() will have no effect if
+ * interrupts have already been disabled.
+ */
+ netif_rx_complete(napi_dev, napi);
+ efx_channel_processed(channel);
+ }
+
+ return rx_packets;
+}
+
+/* Process the eventq of the specified channel immediately on this CPU
+ *
+ * Disable hardware generated interrupts, wait for any existing
+ * processing to finish, then directly poll (and ack ) the eventq.
+ * Finally reenable NAPI and interrupts.
+ *
+ * Since we are touching interrupts the caller should hold the suspend lock
+ */
+void efx_process_channel_now(struct efx_channel *channel)
+{
+ struct efx_nic *efx = channel->efx;
+
+ BUG_ON(!channel->used_flags);
+ BUG_ON(!channel->enabled);
+
+ /* Disable interrupts and wait for ISRs to complete */
+ falcon_disable_interrupts(efx);
+ if (efx->legacy_irq)
+ synchronize_irq(efx->legacy_irq);
+ if (channel->has_interrupt && channel->irq)
+ synchronize_irq(channel->irq);
+
+ /* Wait for any NAPI processing to complete */
+ napi_disable(&channel->napi_str);
+
+ /* Poll the channel */
+ (void) efx_process_channel(channel, efx->type->evq_size);
+
+ /* Ack the eventq. This may cause an interrupt to be generated
+ * when they are reenabled */
+ efx_channel_processed(channel);
+
+ napi_enable(&channel->napi_str);
+ falcon_enable_interrupts(efx);
+}
+
+/* Create event queue
+ * Event queue memory allocations are done only once. If the channel
+ * is reset, the memory buffer will be reused; this guards against
+ * errors during channel reset and also simplifies interrupt handling.
+ */
+static int efx_probe_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
+
+ return falcon_probe_eventq(channel);
+}
+
+/* Prepare channel's event queue */
+static int efx_init_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
+
+ channel->eventq_read_ptr = 0;
+
+ return falcon_init_eventq(channel);
+}
+
+static void efx_fini_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
+
+ falcon_fini_eventq(channel);
+}
+
+static void efx_remove_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
+
+ falcon_remove_eventq(channel);
+}
+
+/**************************************************************************
+ *
+ * Channel handling
+ *
+ *************************************************************************/
+
+/* Setup per-NIC RX buffer parameters.
+ * Calculate the rx buffer allocation parameters required to support
+ * the current MTU, including padding for header alignment and overruns.
+ */
+static void efx_calc_rx_buffer_params(struct efx_nic *efx)
+{
+ unsigned int order, len;
+
+ len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
+ EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+ efx->type->rx_buffer_padding);
+
+ /* Calculate page-order */
+ for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order)
+ ;
+
+ efx->rx_buffer_len = len;
+ efx->rx_buffer_order = order;
+}
+
+static int efx_probe_channel(struct efx_channel *channel)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int rc;
+
+ EFX_LOG(channel->efx, "creating channel %d\n", channel->channel);
+
+ rc = efx_probe_eventq(channel);
+ if (rc)
+ goto fail1;
+
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ rc = efx_probe_tx_queue(tx_queue);
+ if (rc)
+ goto fail2;
+ }
+
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ rc = efx_probe_rx_queue(rx_queue);
+ if (rc)
+ goto fail3;
+ }
+
+ channel->n_rx_frm_trunc = 0;
+
+ return 0;
+
+ fail3:
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_remove_rx_queue(rx_queue);
+ fail2:
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_remove_tx_queue(tx_queue);
+ fail1:
+ return rc;
+}
+
+
+/* Channels are shutdown and reinitialised whilst the NIC is running
+ * to propagate configuration changes (mtu, checksum offload), or
+ * to clear hardware error conditions
+ */
+static int efx_init_channels(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+ int rc = 0;
+
+ efx_calc_rx_buffer_params(efx);
+
+ /* Initialise the channels */
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
+
+ rc = efx_init_eventq(channel);
+ if (rc)
+ goto err;
+
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ rc = efx_init_tx_queue(tx_queue);
+ if (rc)
+ goto err;
+ }
+
+ /* The rx buffer allocation strategy is MTU dependent */
+ efx_rx_strategy(channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ rc = efx_init_rx_queue(rx_queue);
+ if (rc)
+ goto err;
+ }
+
+ WARN_ON(channel->rx_pkt != NULL);
+ efx_rx_strategy(channel);
+ }
+
+ return 0;
+
+ err:
+ EFX_ERR(efx, "failed to initialise channel %d\n",
+ channel ? channel->channel : -1);
+ efx_fini_channels(efx);
+ return rc;
+}
+
+/* This enables event queue processing and packet transmission.
+ *
+ * Note that this function is not allowed to fail, since that would
+ * introduce too much complexity into the suspend/resume path.
+ */
+static void efx_start_channel(struct efx_channel *channel)
+{
+ struct efx_rx_queue *rx_queue;
+
+ EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
+
+ if (!(channel->efx->net_dev->flags & IFF_UP))
+ netif_napi_add(channel->napi_dev, &channel->napi_str,
+ efx_poll, napi_weight);
+
+ channel->work_pending = 0;
+ channel->enabled = 1;
+ smp_wmb(); /* ensure channel updated before first interrupt */
+
+ napi_enable(&channel->napi_str);
+
+ /* Load up RX descriptors */
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_fast_push_rx_descriptors(rx_queue);
+}
+
+/* This disables event queue processing and packet transmission.
+ * This function does not guarantee that all queue processing
+ * (e.g. RX refill) is complete.
+ */
+static void efx_stop_channel(struct efx_channel *channel)
+{
+ struct efx_rx_queue *rx_queue;
+
+ if (!channel->enabled)
+ return;
+
+ EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
+
+ channel->enabled = 0;
+ napi_disable(&channel->napi_str);
+
+ /* Ensure that any worker threads have exited or will be no-ops */
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ spin_lock_bh(&rx_queue->add_lock);
+ spin_unlock_bh(&rx_queue->add_lock);
+ }
+}
+
+static void efx_fini_channels(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+ BUG_ON(efx->port_enabled);
+
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_fini_rx_queue(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_fini_tx_queue(tx_queue);
+ }
+
+ /* Do the event queues last so that we can handle flush events
+ * for all DMA queues. */
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel);
+
+ efx_fini_eventq(channel);
+ }
+}
+
+static void efx_remove_channel(struct efx_channel *channel)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_remove_rx_queue(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_remove_tx_queue(tx_queue);
+ efx_remove_eventq(channel);
+
+ channel->used_flags = 0;
+}
+
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+{
+ queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+}
+
+/**************************************************************************
+ *
+ * Port handling
+ *
+ **************************************************************************/
+
+/* This ensures that the kernel is kept informed (via
+ * netif_carrier_on/off) of the link status, and also maintains the
+ * link status's stop on the port's TX queue.
+ */
+static void efx_link_status_changed(struct efx_nic *efx)
+{
+ int carrier_ok;
+
+ /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
+ * that no events are triggered between unregister_netdev() and the
+ * driver unloading. A more general condition is that NETDEV_CHANGE
+ * can only be generated between NETDEV_UP and NETDEV_DOWN */
+ if (!netif_running(efx->net_dev))
+ return;
+
+ carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0;
+ if (efx->link_up != carrier_ok) {
+ efx->n_link_state_changes++;
+
+ if (efx->link_up)
+ netif_carrier_on(efx->net_dev);
+ else
+ netif_carrier_off(efx->net_dev);
+ }
+
+ /* Status message for kernel log */
+ if (efx->link_up) {
+ struct mii_if_info *gmii = &efx->mii;
+ unsigned adv, lpa;
+ /* NONE here means direct XAUI from the controller, with no
+ * MDIO-attached device we can query. */
+ if (efx->phy_type != PHY_TYPE_NONE) {
+ adv = gmii_advertised(gmii);
+ lpa = gmii_lpa(gmii);
+ } else {
+ lpa = GM_LPA_10000 | LPA_DUPLEX;
+ adv = lpa;
+ }
+ EFX_INFO(efx, "link up at %dMbps %s-duplex "
+ "(adv %04x lpa %04x) (MTU %d)%s\n",
+ (efx->link_options & GM_LPA_10000 ? 10000 :
+ (efx->link_options & GM_LPA_1000 ? 1000 :
+ (efx->link_options & GM_LPA_100 ? 100 :
+ 10))),
+ (efx->link_options & GM_LPA_DUPLEX ?
+ "full" : "half"),
+ adv, lpa,
+ efx->net_dev->mtu,
+ (efx->promiscuous ? " [PROMISC]" : ""));
+ } else {
+ EFX_INFO(efx, "link down\n");
+ }
+
+}
+
+/* This call reinitialises the MAC to pick up new PHY settings. The
+ * caller must hold the mac_lock */
+static void __efx_reconfigure_port(struct efx_nic *efx)
+{
+ WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+ EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
+ raw_smp_processor_id());
+
+ falcon_reconfigure_xmac(efx);
+
+ /* Inform kernel of loss/gain of carrier */
+ efx_link_status_changed(efx);
+}
+
+/* Reinitialise the MAC to pick up new PHY settings, even if the port is
+ * disabled. */
+void efx_reconfigure_port(struct efx_nic *efx)
+{
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ mutex_lock(&efx->mac_lock);
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all()
+ * we don't efx_reconfigure_port() if the port is disabled. Care is taken
+ * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */
+static void efx_reconfigure_work(struct work_struct *data)
+{
+ struct efx_nic *efx = container_of(data, struct efx_nic,
+ reconfigure_work);
+
+ mutex_lock(&efx->mac_lock);
+ if (efx->port_enabled)
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+static int efx_probe_port(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "create port\n");
+
+ /* Connect up MAC/PHY operations table and read MAC address */
+ rc = falcon_probe_port(efx);
+ if (rc)
+ goto err;
+
+ /* Sanity check MAC address */
+ if (is_valid_ether_addr(efx->mac_address)) {
+ memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
+ } else {
+ DECLARE_MAC_BUF(mac);
+
+ EFX_ERR(efx, "invalid MAC address %s\n",
+ print_mac(mac, efx->mac_address));
+ if (!allow_bad_hwaddr) {
+ rc = -EINVAL;
+ goto err;
+ }
+ random_ether_addr(efx->net_dev->dev_addr);
+ EFX_INFO(efx, "using locally-generated MAC %s\n",
+ print_mac(mac, efx->net_dev->dev_addr));
+ }
+
+ return 0;
+
+ err:
+ efx_remove_port(efx);
+ return rc;
+}
+
+static int efx_init_port(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "init port\n");
+
+ /* Initialise the MAC and PHY */
+ rc = falcon_init_xmac(efx);
+ if (rc)
+ return rc;
+
+ efx->port_initialized = 1;
+
+ /* Reconfigure port to program MAC registers */
+ falcon_reconfigure_xmac(efx);
+
+ return 0;
+}
+
+/* Allow efx_reconfigure_port() to be scheduled, and close the window
+ * between efx_stop_port and efx_flush_all whereby a previously scheduled
+ * efx_reconfigure_port() may have been cancelled */
+static void efx_start_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "start port\n");
+ BUG_ON(efx->port_enabled);
+
+ mutex_lock(&efx->mac_lock);
+ efx->port_enabled = 1;
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+/* Prevent efx_reconfigure_work and efx_monitor() from executing, and
+ * efx_set_multicast_list() from scheduling efx_reconfigure_work.
+ * efx_reconfigure_work can still be scheduled via NAPI processing
+ * until efx_flush_all() is called */
+static void efx_stop_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "stop port\n");
+
+ mutex_lock(&efx->mac_lock);
+ efx->port_enabled = 0;
+ mutex_unlock(&efx->mac_lock);
+
+ /* Serialise against efx_set_multicast_list() */
+ if (NET_DEV_REGISTERED(efx)) {
+ netif_tx_lock_bh(efx->net_dev);
+ netif_tx_unlock_bh(efx->net_dev);
+ }
+}
+
+static void efx_fini_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "shut down port\n");
+
+ if (!efx->port_initialized)
+ return;
+
+ falcon_fini_xmac(efx);
+ efx->port_initialized = 0;
+
+ efx->link_up = 0;
+ efx_link_status_changed(efx);
+}
+
+static void efx_remove_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "destroying port\n");
+
+ falcon_remove_port(efx);
+}
+
+/**************************************************************************
+ *
+ * NIC handling
+ *
+ **************************************************************************/
+
+/* This configures the PCI device to enable I/O and DMA. */
+static int efx_init_io(struct efx_nic *efx)
+{
+ struct pci_dev *pci_dev = efx->pci_dev;
+ dma_addr_t dma_mask = efx->type->max_dma_mask;
+ int rc;
+
+ EFX_LOG(efx, "initialising I/O\n");
+
+ rc = pci_enable_device(pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to enable PCI device\n");
+ goto fail1;
+ }
+
+ pci_set_master(pci_dev);
+
+ /* Set the PCI DMA mask. Try all possibilities from our
+ * genuine mask down to 32 bits, because some architectures
+ * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit
+ * masks event though they reject 46 bit masks.
+ */
+ while (dma_mask > 0x7fffffffUL) {
+ if (pci_dma_supported(pci_dev, dma_mask) &&
+ ((rc = pci_set_dma_mask(pci_dev, dma_mask)) == 0))
+ break;
+ dma_mask >>= 1;
+ }
+ if (rc) {
+ EFX_ERR(efx, "could not find a suitable DMA mask\n");
+ goto fail2;
+ }
+ EFX_LOG(efx, "using DMA mask %llx\n", (unsigned long long) dma_mask);
+ rc = pci_set_consistent_dma_mask(pci_dev, dma_mask);
+ if (rc) {
+ /* pci_set_consistent_dma_mask() is not *allowed* to
+ * fail with a mask that pci_set_dma_mask() accepted,
+ * but just in case...
+ */
+ EFX_ERR(efx, "failed to set consistent DMA mask\n");
+ goto fail2;
+ }
+
+ efx->membase_phys = pci_resource_start(efx->pci_dev,
+ efx->type->mem_bar);
+ rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc");
+ if (rc) {
+ EFX_ERR(efx, "request for memory BAR failed\n");
+ rc = -EIO;
+ goto fail3;
+ }
+ efx->membase = ioremap_nocache(efx->membase_phys,
+ efx->type->mem_map_size);
+ if (!efx->membase) {
+ EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n",
+ efx->type->mem_bar, efx->membase_phys,
+ efx->type->mem_map_size);
+ rc = -ENOMEM;
+ goto fail4;
+ }
+ EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n",
+ efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size,
+ efx->membase);
+
+ return 0;
+
+ fail4:
+ release_mem_region(efx->membase_phys, efx->type->mem_map_size);
+ fail3:
+ efx->membase_phys = 0UL;
+ fail2:
+ pci_disable_device(efx->pci_dev);
+ fail1:
+ return rc;
+}
+
+static void efx_fini_io(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "shutting down I/O\n");
+
+ if (efx->membase) {
+ iounmap(efx->membase);
+ efx->membase = NULL;
+ }
+
+ if (efx->membase_phys) {
+ pci_release_region(efx->pci_dev, efx->type->mem_bar);
+ efx->membase_phys = 0UL;
+ }
+
+ pci_disable_device(efx->pci_dev);
+}
+
+/* Probe the number and type of interrupts we are able to obtain. */
+static void efx_probe_interrupts(struct efx_nic *efx)
+{
+ int max_channel = efx->type->phys_addr_channels - 1;
+ struct msix_entry xentries[EFX_MAX_CHANNELS];
+ int rc, i;
+
+ if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
+ BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
+
+ efx->rss_queues = rss_cpus ? rss_cpus : num_online_cpus();
+ efx->rss_queues = min(efx->rss_queues, max_channel + 1);
+ efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
+
+ /* Request maximum number of MSI interrupts, and fill out
+ * the channel interrupt information the allowed allocation */
+ for (i = 0; i < efx->rss_queues; i++)
+ xentries[i].entry = i;
+ rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
+ if (rc > 0) {
+ EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
+ efx->rss_queues = rc;
+ rc = pci_enable_msix(efx->pci_dev, xentries,
+ efx->rss_queues);
+ }
+
+ if (rc == 0) {
+ for (i = 0; i < efx->rss_queues; i++) {
+ efx->channel[i].has_interrupt = 1;
+ efx->channel[i].irq = xentries[i].vector;
+ }
+ } else {
+ /* Fall back to single channel MSI */
+ efx->interrupt_mode = EFX_INT_MODE_MSI;
+ EFX_ERR(efx, "could not enable MSI-X\n");
+ }
+ }
+
+ /* Try single interrupt MSI */
+ if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
+ efx->rss_queues = 1;
+ rc = pci_enable_msi(efx->pci_dev);
+ if (rc == 0) {
+ efx->channel[0].irq = efx->pci_dev->irq;
+ efx->channel[0].has_interrupt = 1;
+ } else {
+ EFX_ERR(efx, "could not enable MSI\n");
+ efx->interrupt_mode = EFX_INT_MODE_LEGACY;
+ }
+ }
+
+ /* Assume legacy interrupts */
+ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
+ efx->rss_queues = 1;
+ /* Every channel is interruptible */
+ for (i = 0; i < EFX_MAX_CHANNELS; i++)
+ efx->channel[i].has_interrupt = 1;
+ efx->legacy_irq = efx->pci_dev->irq;
+ }
+}
+
+static void efx_remove_interrupts(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ /* Remove MSI/MSI-X interrupts */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ channel->irq = 0;
+ pci_disable_msi(efx->pci_dev);
+ pci_disable_msix(efx->pci_dev);
+
+ /* Remove legacy interrupt */
+ efx->legacy_irq = 0;
+}
+
+/* Select number of used resources
+ * Should be called after probe_interrupts()
+ */
+static void efx_select_used(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int i;
+
+ /* TX queues. One per port per channel with TX capability
+ * (more than one per port won't work on Linux, due to out
+ * of order issues... but will be fine on Solaris)
+ */
+ tx_queue = &efx->tx_queue[0];
+
+ /* Perform this for each channel with TX capabilities.
+ * At the moment, we only support a single TX queue
+ */
+ tx_queue->used = 1;
+ if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
+ tx_queue->channel = &efx->channel[1];
+ else
+ tx_queue->channel = &efx->channel[0];
+ tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+ tx_queue++;
+
+ /* RX queues. Each has a dedicated channel. */
+ for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
+ rx_queue = &efx->rx_queue[i];
+
+ if (i < efx->rss_queues) {
+ rx_queue->used = 1;
+ /* If we allow multiple RX queues per channel
+ * we need to decide that here
+ */
+ rx_queue->channel = &efx->channel[rx_queue->queue];
+ rx_queue->channel->used_flags |= EFX_USED_BY_RX;
+ rx_queue++;
+ }
+ }
+}
+
+static int efx_probe_nic(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "creating NIC\n");
+
+ /* Carry out hardware-type specific initialisation */
+ rc = falcon_probe_nic(efx);
+ if (rc)
+ return rc;
+
+ /* Determine the number of channels and RX queues by trying to hook
+ * in MSI-X interrupts. */
+ efx_probe_interrupts(efx);
+
+ /* Determine number of RX queues and TX queues */
+ efx_select_used(efx);
+
+ /* Initialise the interrupt moderation settings */
+ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
+
+ return 0;
+}
+
+static void efx_remove_nic(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "destroying NIC\n");
+
+ efx_remove_interrupts(efx);
+ falcon_remove_nic(efx);
+}
+
+/**************************************************************************
+ *
+ * NIC startup/shutdown
+ *
+ *************************************************************************/
+
+static int efx_probe_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ /* Create NIC */
+ rc = efx_probe_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to create NIC\n");
+ goto fail1;
+ }
+
+ /* Create port */
+ rc = efx_probe_port(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to create port\n");
+ goto fail2;
+ }
+
+ /* Create channels */
+ efx_for_each_channel(channel, efx) {
+ rc = efx_probe_channel(channel);
+ if (rc) {
+ EFX_ERR(efx, "failed to create channel %d\n",
+ channel->channel);
+ goto fail3;
+ }
+ }
+
+ return 0;
+
+ fail3:
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+ efx_remove_port(efx);
+ fail2:
+ efx_remove_nic(efx);
+ fail1:
+ return rc;
+}
+
+/* Called after previous invocation(s) of efx_stop_all, restarts the
+ * port, kernel transmit queue, NAPI processing and hardware interrupts,
+ * and ensures that the port is scheduled to be reconfigured.
+ * This function is safe to call multiple times when the NIC is in any
+ * state. */
+static void efx_start_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* Check that it is appropriate to restart the interface. All
+ * of these flags are safe to read under just the rtnl lock */
+ if (efx->port_enabled)
+ return;
+ if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT))
+ return;
+ if (NET_DEV_REGISTERED(efx) && !netif_running(efx->net_dev))
+ return;
+
+ /* Mark the port as enabled so port reconfigurations can start, then
+ * restart the transmit interface early so the watchdog timer stops */
+ efx_start_port(efx);
+ efx_wake_queue(efx);
+
+ efx_for_each_channel(channel, efx)
+ efx_start_channel(channel);
+
+ falcon_enable_interrupts(efx);
+
+ /* Start hardware monitor if we're in RUNNING */
+ if (efx->state == STATE_RUNNING)
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+}
+
+/* Flush all delayed work. Should only be called when no more delayed work
+ * will be scheduled. This doesn't flush pending online resets (efx_reset),
+ * since we're holding the rtnl_lock at this point. */
+static void efx_flush_all(struct efx_nic *efx)
+{
+ struct efx_rx_queue *rx_queue;
+
+ /* Make sure the hardware monitor is stopped */
+ cancel_delayed_work_sync(&efx->monitor_work);
+
+ /* Ensure that all RX slow refills are complete. */
+ efx_for_each_rx_queue(rx_queue, efx) {
+ cancel_delayed_work_sync(&rx_queue->work);
+ }
+
+ /* Stop scheduled port reconfigurations */
+ cancel_work_sync(&efx->reconfigure_work);
+
+}
+
+/* Quiesce hardware and software without bringing the link down.
+ * Safe to call multiple times, when the nic and interface is in any
+ * state. The caller is guaranteed to subsequently be in a position
+ * to modify any hardware and software state they see fit without
+ * taking locks. */
+static void efx_stop_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* port_enabled can be read safely under the rtnl lock */
+ if (!efx->port_enabled)
+ return;
+
+ /* Disable interrupts and wait for ISR to complete */
+ falcon_disable_interrupts(efx);
+ if (efx->legacy_irq)
+ synchronize_irq(efx->legacy_irq);
+ efx_for_each_channel_with_interrupt(channel, efx)
+ if (channel->irq)
+ synchronize_irq(channel->irq);
+
+ /* Stop all NAPI processing and synchronous rx refills */
+ efx_for_each_channel(channel, efx)
+ efx_stop_channel(channel);
+
+ /* Stop all asynchronous port reconfigurations. Since all
+ * event processing has already been stopped, there is no
+ * window to loose phy events */
+ efx_stop_port(efx);
+
+ /* Flush reconfigure_work, refill_workqueue, monitor_work */
+ efx_flush_all(efx);
+
+ /* Isolate the MAC from the TX and RX engines, so that queue
+ * flushes will complete in a timely fashion. */
+ falcon_deconfigure_mac_wrapper(efx);
+ falcon_drain_tx_fifo(efx);
+
+ /* Stop the kernel transmit interface late, so the watchdog
+ * timer isn't ticking over the flush */
+ efx_stop_queue(efx);
+ if (NET_DEV_REGISTERED(efx)) {
+ netif_tx_lock_bh(efx->net_dev);
+ netif_tx_unlock_bh(efx->net_dev);
+ }
+}
+
+static void efx_remove_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+ efx_remove_port(efx);
+ efx_remove_nic(efx);
+}
+
+/* A convinience function to safely flush all the queues */
+int efx_flush_queues(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ efx_stop_all(efx);
+
+ efx_fini_channels(efx);
+ rc = efx_init_channels(efx);
+ if (rc) {
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ return rc;
+ }
+
+ efx_start_all(efx);
+
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * Interrupt moderation
+ *
+ **************************************************************************/
+
+/* Set interrupt moderation parameters */
+void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ efx_for_each_tx_queue(tx_queue, efx)
+ tx_queue->channel->irq_moderation = tx_usecs;
+
+ efx_for_each_rx_queue(rx_queue, efx)
+ rx_queue->channel->irq_moderation = rx_usecs;
+}
+
+/**************************************************************************
+ *
+ * Hardware monitor
+ *
+ **************************************************************************/
+
+/* Run periodically off the general workqueue. Serialised against
+ * efx_reconfigure_port via the mac_lock */
+static void efx_monitor(struct work_struct *data)
+{
+ struct efx_nic *efx = container_of(data, struct efx_nic,
+ monitor_work.work);
+ int rc = 0;
+
+ EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
+ raw_smp_processor_id());
+
+
+ /* If the mac_lock is already held then it is likely a port
+ * reconfiguration is already in place, which will likely do
+ * most of the work of check_hw() anyway. */
+ if (!mutex_trylock(&efx->mac_lock)) {
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+ return;
+ }
+
+ if (efx->port_enabled)
+ rc = falcon_check_xmac(efx);
+ mutex_unlock(&efx->mac_lock);
+
+ if (rc) {
+ if (monitor_reset) {
+ EFX_ERR(efx, "hardware monitor detected a fault: "
+ "triggering reset\n");
+ efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+ } else {
+ EFX_ERR(efx, "hardware monitor detected a fault, "
+ "skipping reset\n");
+ }
+ }
+
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+}
+
+/**************************************************************************
+ *
+ * ioctls
+ *
+ *************************************************************************/
+
+/* Net device ioctl
+ * Context: process, rtnl_lock() held.
+ */
+static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
+}
+
+/**************************************************************************
+ *
+ * NAPI interface
+ *
+ **************************************************************************/
+
+static int efx_init_napi(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ efx_for_each_channel(channel, efx) {
+ channel->napi_dev = efx->net_dev;
+ rc = efx_lro_init(&channel->lro_mgr, efx);
+ if (rc)
+ goto err;
+ }
+ return 0;
+ err:
+ efx_fini_napi(efx);
+ return rc;
+}
+
+static void efx_fini_napi(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx) {
+ efx_lro_fini(&channel->lro_mgr);
+ channel->napi_dev = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * Kernel netpoll interface
+ *
+ *************************************************************************/
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/* Although in the common case interrupts will be disabled, this is not
+ * guaranteed. However, all our work happens inside the NAPI callback,
+ * so no locking is required.
+ */
+static void efx_netpoll(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_channel *channel;
+
+ efx_for_each_channel_with_interrupt(channel, efx)
+ efx_schedule_channel(channel);
+}
+
+#endif
+
+/**************************************************************************
+ *
+ * Kernel net device interface
+ *
+ *************************************************************************/
+
+/* Context: process, rtnl_lock() held. */
+static int efx_net_open(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
+ raw_smp_processor_id());
+
+ efx_start_all(efx);
+ return 0;
+}
+
+/* Context: process, rtnl_lock() held.
+ * Note that the kernel will ignore our return code; this method
+ * should really be a void.
+ */
+static int efx_net_stop(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
+ raw_smp_processor_id());
+
+ /* Stop the device and flush all the channels */
+ efx_stop_all(efx);
+ efx_fini_channels(efx);
+ rc = efx_init_channels(efx);
+ if (rc)
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+
+ return 0;
+}
+
+/* Context: process, dev_base_lock held, non-blocking. */
+static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ struct net_device_stats *stats = &net_dev->stats;
+
+ if (!spin_trylock(&efx->stats_lock))
+ return stats;
+ if (efx->state == STATE_RUNNING) {
+ falcon_update_stats_xmac(efx);
+ falcon_update_nic_stats(efx);
+ }
+ spin_unlock(&efx->stats_lock);
+
+ stats->rx_packets = mac_stats->rx_packets;
+ stats->tx_packets = mac_stats->tx_packets;
+ stats->rx_bytes = mac_stats->rx_bytes;
+ stats->tx_bytes = mac_stats->tx_bytes;
+ stats->multicast = mac_stats->rx_multicast;
+ stats->collisions = mac_stats->tx_collision;
+ stats->rx_length_errors = (mac_stats->rx_gtjumbo +
+ mac_stats->rx_length_error);
+ stats->rx_over_errors = efx->n_rx_nodesc_drop_cnt;
+ stats->rx_crc_errors = mac_stats->rx_bad;
+ stats->rx_frame_errors = mac_stats->rx_align_error;
+ stats->rx_fifo_errors = mac_stats->rx_overflow;
+ stats->rx_missed_errors = mac_stats->rx_missed;
+ stats->tx_window_errors = mac_stats->tx_late_collision;
+
+ stats->rx_errors = (stats->rx_length_errors +
+ stats->rx_over_errors +
+ stats->rx_crc_errors +
+ stats->rx_frame_errors +
+ stats->rx_fifo_errors +
+ stats->rx_missed_errors +
+ mac_stats->rx_symbol_error);
+ stats->tx_errors = (stats->tx_window_errors +
+ mac_stats->tx_bad);
+
+ return stats;
+}
+
+/* Context: netif_tx_lock held, BHs disabled. */
+static void efx_watchdog(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
+ atomic_read(&efx->netif_stop_count), efx->port_enabled,
+ monitor_reset ? "resetting channels" : "skipping reset");
+
+ if (monitor_reset)
+ efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+}
+
+
+/* Context: process, rtnl_lock() held. */
+static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc = 0;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ if (new_mtu > EFX_MAX_MTU)
+ return -EINVAL;
+
+ efx_stop_all(efx);
+
+ EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
+
+ efx_fini_channels(efx);
+ net_dev->mtu = new_mtu;
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail;
+
+ efx_start_all(efx);
+ return rc;
+
+ fail:
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ return rc;
+}
+
+static int efx_set_mac_address(struct net_device *net_dev, void *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct sockaddr *addr = data;
+ char *new_addr = addr->sa_data;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ if (!is_valid_ether_addr(new_addr)) {
+ DECLARE_MAC_BUF(mac);
+ EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n",
+ print_mac(mac, new_addr));
+ return -EINVAL;
+ }
+
+ memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
+
+ /* Reconfigure the MAC */
+ efx_reconfigure_port(efx);
+
+ return 0;
+}
+
+/* Context: netif_tx_lock held, BHs disabled. */
+static void efx_set_multicast_list(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct dev_mc_list *mc_list = net_dev->mc_list;
+ union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+ int promiscuous;
+ u32 crc;
+ int bit;
+ int i;
+
+ /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */
+ promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0;
+ if (efx->promiscuous != promiscuous) {
+ efx->promiscuous = promiscuous;
+ /* Close the window between efx_stop_port() and efx_flush_all()
+ * by only queuing work when the port is enabled. */
+ if (efx->port_enabled)
+ queue_work(efx->workqueue, &efx->reconfigure_work);
+ }
+
+ /* Build multicast hash table */
+ if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+ memset(mc_hash, 0xff, sizeof(*mc_hash));
+ } else {
+ memset(mc_hash, 0x00, sizeof(*mc_hash));
+ for (i = 0; i < net_dev->mc_count; i++) {
+ crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr);
+ bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
+ set_bit_le(bit, mc_hash->byte);
+ mc_list = mc_list->next;
+ }
+ }
+
+ /* Create and activate new global multicast hash table */
+ falcon_set_multicast_hash(efx);
+}
+
+static int efx_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *net_dev = (struct net_device *)ptr;
+
+ if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
+ struct efx_nic *efx = net_dev->priv;
+
+ strcpy(efx->name, net_dev->name);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block efx_netdev_notifier = {
+ .notifier_call = efx_netdev_event,
+};
+
+static int efx_register_netdev(struct efx_nic *efx)
+{
+ struct net_device *net_dev = efx->net_dev;
+ int rc;
+
+ net_dev->watchdog_timeo = 5 * HZ;
+ net_dev->irq = efx->pci_dev->irq;
+ net_dev->open = efx_net_open;
+ net_dev->stop = efx_net_stop;
+ net_dev->get_stats = efx_net_stats;
+ net_dev->tx_timeout = &efx_watchdog;
+ net_dev->hard_start_xmit = efx_hard_start_xmit;
+ net_dev->do_ioctl = efx_ioctl;
+ net_dev->change_mtu = efx_change_mtu;
+ net_dev->set_mac_address = efx_set_mac_address;
+ net_dev->set_multicast_list = efx_set_multicast_list;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ net_dev->poll_controller = efx_netpoll;
+#endif
+ SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
+ SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
+
+ /* Always start with carrier off; PHY events will detect the link */
+ netif_carrier_off(efx->net_dev);
+
+ /* Clear MAC statistics */
+ falcon_update_stats_xmac(efx);
+ memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
+
+ rc = register_netdev(net_dev);
+ if (rc) {
+ EFX_ERR(efx, "could not register net dev\n");
+ return rc;
+ }
+ strcpy(efx->name, net_dev->name);
+
+ return 0;
+}
+
+static void efx_unregister_netdev(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+
+ if (!efx->net_dev)
+ return;
+
+ BUG_ON(efx->net_dev->priv != efx);
+
+ /* Free up any skbs still remaining. This has to happen before
+ * we try to unregister the netdev as running their destructors
+ * may be needed to get the device ref. count to 0. */
+ efx_for_each_tx_queue(tx_queue, efx)
+ efx_release_tx_buffers(tx_queue);
+
+ if (NET_DEV_REGISTERED(efx)) {
+ strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
+ unregister_netdev(efx->net_dev);
+ }
+}
+
+/**************************************************************************
+ *
+ * Device reset and suspend
+ *
+ **************************************************************************/
+
+/* The final hardware and software finalisation before reset. */
+static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ int rc;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ rc = falcon_xmac_get_settings(efx, ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not back up PHY settings\n");
+ goto fail;
+ }
+
+ efx_fini_channels(efx);
+ return 0;
+
+ fail:
+ return rc;
+}
+
+/* The first part of software initialisation after a hardware reset
+ * This function does not handle serialisation with the kernel, it
+ * assumes the caller has done this */
+static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ int rc;
+
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail1;
+
+ /* Restore MAC and PHY settings. */
+ rc = falcon_xmac_set_settings(efx, ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not restore PHY settings\n");
+ goto fail2;
+ }
+
+ return 0;
+
+ fail2:
+ efx_fini_channels(efx);
+ fail1:
+ return rc;
+}
+
+/* Reset the NIC as transparently as possible. Do not reset the PHY
+ * Note that the reset may fail, in which case the card will be left
+ * in a most-probably-unusable state.
+ *
+ * This function will sleep. You cannot reset from within an atomic
+ * state; use efx_schedule_reset() instead.
+ *
+ * Grabs the rtnl_lock.
+ */
+static int efx_reset(struct efx_nic *efx)
+{
+ struct ethtool_cmd ecmd;
+ enum reset_type method = efx->reset_pending;
+ int rc;
+
+ /* Serialise with kernel interfaces */
+ rtnl_lock();
+
+ /* If we're not RUNNING then don't reset. Leave the reset_pending
+ * flag set so that efx_pci_probe_main will be retried */
+ if (efx->state != STATE_RUNNING) {
+ EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
+ goto unlock_rtnl;
+ }
+
+ efx->state = STATE_RESETTING;
+ EFX_INFO(efx, "resetting (%d)\n", method);
+
+ /* The net_dev->get_stats handler is quite slow, and will fail
+ * if a fetch is pending over reset. Serialise against it. */
+ spin_lock(&efx->stats_lock);
+ spin_unlock(&efx->stats_lock);
+
+ efx_stop_all(efx);
+ mutex_lock(&efx->mac_lock);
+
+ rc = efx_reset_down(efx, &ecmd);
+ if (rc)
+ goto fail1;
+
+ rc = falcon_reset_hw(efx, method);
+ if (rc) {
+ EFX_ERR(efx, "failed to reset hardware\n");
+ goto fail2;
+ }
+
+ /* Allow resets to be rescheduled. */
+ efx->reset_pending = RESET_TYPE_NONE;
+
+ /* Reinitialise bus-mastering, which may have been turned off before
+ * the reset was scheduled. This is still appropriate, even in the
+ * RESET_TYPE_DISABLE since this driver generally assumes the hardware
+ * can respond to requests. */
+ pci_set_master(efx->pci_dev);
+
+ /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE
+ * case so the driver can talk to external SRAM */
+ rc = falcon_init_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise NIC\n");
+ goto fail3;
+ }
+
+ /* Leave device stopped if necessary */
+ if (method == RESET_TYPE_DISABLE) {
+ /* Reinitialise the device anyway so the driver unload sequence
+ * can talk to the external SRAM */
+ (void) falcon_init_nic(efx);
+ rc = -EIO;
+ goto fail4;
+ }
+
+ rc = efx_reset_up(efx, &ecmd);
+ if (rc)
+ goto fail5;
+
+ mutex_unlock(&efx->mac_lock);
+ EFX_LOG(efx, "reset complete\n");
+
+ efx->state = STATE_RUNNING;
+ efx_start_all(efx);
+
+ unlock_rtnl:
+ rtnl_unlock();
+ return 0;
+
+ fail5:
+ fail4:
+ fail3:
+ fail2:
+ fail1:
+ EFX_ERR(efx, "has been disabled\n");
+ efx->state = STATE_DISABLED;
+
+ mutex_unlock(&efx->mac_lock);
+ rtnl_unlock();
+ efx_unregister_netdev(efx);
+ efx_fini_port(efx);
+ return rc;
+}
+
+/* The worker thread exists so that code that cannot sleep can
+ * schedule a reset for later.
+ */
+static void efx_reset_work(struct work_struct *data)
+{
+ struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
+
+ efx_reset(nic);
+}
+
+void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
+{
+ enum reset_type method;
+
+ if (efx->reset_pending != RESET_TYPE_NONE) {
+ EFX_INFO(efx, "quenching already scheduled reset\n");
+ return;
+ }
+
+ switch (type) {
+ case RESET_TYPE_INVISIBLE:
+ case RESET_TYPE_ALL:
+ case RESET_TYPE_WORLD:
+ case RESET_TYPE_DISABLE:
+ method = type;
+ break;
+ case RESET_TYPE_RX_RECOVERY:
+ case RESET_TYPE_RX_DESC_FETCH:
+ case RESET_TYPE_TX_DESC_FETCH:
+ case RESET_TYPE_TX_SKIP:
+ method = RESET_TYPE_INVISIBLE;
+ break;
+ default:
+ method = RESET_TYPE_ALL;
+ break;
+ }
+
+ if (method != type)
+ EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method);
+ else
+ EFX_LOG(efx, "scheduling reset (%d)\n", method);
+
+ efx->reset_pending = method;
+
+ queue_work(efx->workqueue, &efx->reset_work);
+}
+
+/**************************************************************************
+ *
+ * List of NICs we support
+ *
+ **************************************************************************/
+
+/* PCI device ID table */
+static struct pci_device_id efx_pci_table[] __devinitdata = {
+ {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
+ .driver_data = (unsigned long) &falcon_a_nic_type},
+ {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
+ .driver_data = (unsigned long) &falcon_b_nic_type},
+ {0} /* end of list */
+};
+
+/**************************************************************************
+ *
+ * Dummy PHY/MAC/Board operations
+ *
+ * Can be used where the MAC does not implement this operation
+ * Needed so all function pointers are valid and do not have to be tested
+ * before use
+ *
+ **************************************************************************/
+int efx_port_dummy_op_int(struct efx_nic *efx)
+{
+ return 0;
+}
+void efx_port_dummy_op_void(struct efx_nic *efx) {}
+void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {}
+
+static struct efx_phy_operations efx_dummy_phy_operations = {
+ .init = efx_port_dummy_op_int,
+ .reconfigure = efx_port_dummy_op_void,
+ .check_hw = efx_port_dummy_op_int,
+ .fini = efx_port_dummy_op_void,
+ .clear_interrupt = efx_port_dummy_op_void,
+ .reset_xaui = efx_port_dummy_op_void,
+};
+
+/* Dummy board operations */
+static int efx_nic_dummy_op_int(struct efx_nic *nic)
+{
+ return 0;
+}
+
+static struct efx_board efx_dummy_board_info = {
+ .init = efx_nic_dummy_op_int,
+ .init_leds = efx_port_dummy_op_int,
+ .set_fault_led = efx_port_dummy_op_blink,
+};
+
+/**************************************************************************
+ *
+ * Data housekeeping
+ *
+ **************************************************************************/
+
+/* This zeroes out and then fills in the invariants in a struct
+ * efx_nic (including all sub-structures).
+ */
+static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
+ struct pci_dev *pci_dev, struct net_device *net_dev)
+{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int i, rc;
+
+ /* Initialise common structures */
+ memset(efx, 0, sizeof(*efx));
+ spin_lock_init(&efx->biu_lock);
+ spin_lock_init(&efx->phy_lock);
+ INIT_WORK(&efx->reset_work, efx_reset_work);
+ INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
+ efx->pci_dev = pci_dev;
+ efx->state = STATE_INIT;
+ efx->reset_pending = RESET_TYPE_NONE;
+ strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
+ efx->board_info = efx_dummy_board_info;
+
+ efx->net_dev = net_dev;
+ efx->rx_checksum_enabled = 1;
+ spin_lock_init(&efx->netif_stop_lock);
+ spin_lock_init(&efx->stats_lock);
+ mutex_init(&efx->mac_lock);
+ efx->phy_op = &efx_dummy_phy_operations;
+ efx->mii.dev = net_dev;
+ INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
+ atomic_set(&efx->netif_stop_count, 1);
+
+ for (i = 0; i < EFX_MAX_CHANNELS; i++) {
+ channel = &efx->channel[i];
+ channel->efx = efx;
+ channel->channel = i;
+ channel->evqnum = i;
+ channel->work_pending = 0;
+ }
+ for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+ tx_queue = &efx->tx_queue[i];
+ tx_queue->efx = efx;
+ tx_queue->queue = i;
+ tx_queue->buffer = NULL;
+ tx_queue->channel = &efx->channel[0]; /* for safety */
+ }
+ for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
+ rx_queue = &efx->rx_queue[i];
+ rx_queue->efx = efx;
+ rx_queue->queue = i;
+ rx_queue->channel = &efx->channel[0]; /* for safety */
+ rx_queue->buffer = NULL;
+ spin_lock_init(&rx_queue->add_lock);
+ INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+ }
+
+ efx->type = type;
+
+ /* Sanity-check NIC type */
+ EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask &
+ (efx->type->txd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask &
+ (efx->type->rxd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->evq_size &
+ (efx->type->evq_size - 1));
+ /* As close as we can get to guaranteeing that we don't overflow */
+ EFX_BUG_ON_PARANOID(efx->type->evq_size <
+ (efx->type->txd_ring_mask + 1 +
+ efx->type->rxd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS);
+
+ /* Higher numbered interrupt modes are less capable! */
+ efx->interrupt_mode = max(efx->type->max_interrupt_mode,
+ interrupt_mode);
+
+ efx->workqueue = create_singlethread_workqueue("sfc_work");
+ if (!efx->workqueue) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ return 0;
+
+ fail1:
+ return rc;
+}
+
+static void efx_fini_struct(struct efx_nic *efx)
+{
+ if (efx->workqueue) {
+ destroy_workqueue(efx->workqueue);
+ efx->workqueue = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * PCI interface
+ *
+ **************************************************************************/
+
+/* Main body of final NIC shutdown code
+ * This is called only at module unload (or hotplug removal).
+ */
+static void efx_pci_remove_main(struct efx_nic *efx)
+{
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* Skip everything if we never obtained a valid membase */
+ if (!efx->membase)
+ return;
+
+ efx_fini_channels(efx);
+ efx_fini_port(efx);
+
+ /* Shutdown the board, then the NIC and board state */
+ falcon_fini_interrupt(efx);
+
+ efx_fini_napi(efx);
+ efx_remove_all(efx);
+}
+
+/* Final NIC shutdown
+ * This is called only at module unload (or hotplug removal).
+ */
+static void efx_pci_remove(struct pci_dev *pci_dev)
+{
+ struct efx_nic *efx;
+
+ efx = pci_get_drvdata(pci_dev);
+ if (!efx)
+ return;
+
+ /* Mark the NIC as fini, then stop the interface */
+ rtnl_lock();
+ efx->state = STATE_FINI;
+ dev_close(efx->net_dev);
+
+ /* Allow any queued efx_resets() to complete */
+ rtnl_unlock();
+
+ if (efx->membase == NULL)
+ goto out;
+
+ efx_unregister_netdev(efx);
+
+ /* Wait for any scheduled resets to complete. No more will be
+ * scheduled from this point because efx_stop_all() has been
+ * called, we are no longer registered with driverlink, and
+ * the net_device's have been removed. */
+ flush_workqueue(efx->workqueue);
+
+ efx_pci_remove_main(efx);
+
+out:
+ efx_fini_io(efx);
+ EFX_LOG(efx, "shutdown successful\n");
+
+ pci_set_drvdata(pci_dev, NULL);
+ efx_fini_struct(efx);
+ free_netdev(efx->net_dev);
+};
+
+/* Main body of NIC initialisation
+ * This is called at module load (or hotplug insertion, theoretically).
+ */
+static int efx_pci_probe_main(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Do start-of-day initialisation */
+ rc = efx_probe_all(efx);
+ if (rc)
+ goto fail1;
+
+ rc = efx_init_napi(efx);
+ if (rc)
+ goto fail2;
+
+ /* Initialise the board */
+ rc = efx->board_info.init(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise board\n");
+ goto fail3;
+ }
+
+ rc = falcon_init_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise NIC\n");
+ goto fail4;
+ }
+
+ rc = efx_init_port(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise port\n");
+ goto fail5;
+ }
+
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail6;
+
+ rc = falcon_init_interrupt(efx);
+ if (rc)
+ goto fail7;
+
+ return 0;
+
+ fail7:
+ efx_fini_channels(efx);
+ fail6:
+ efx_fini_port(efx);
+ fail5:
+ fail4:
+ fail3:
+ efx_fini_napi(efx);
+ fail2:
+ efx_remove_all(efx);
+ fail1:
+ return rc;
+}
+
+/* NIC initialisation
+ *
+ * This is called at module load (or hotplug insertion,
+ * theoretically). It sets up PCI mappings, tests and resets the NIC,
+ * sets up and registers the network devices with the kernel and hooks
+ * the interrupt service routine. It does not prepare the device for
+ * transmission; this is left to the first time one of the network
+ * interfaces is brought up (i.e. efx_net_open).
+ */
+static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *entry)
+{
+ struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
+ struct net_device *net_dev;
+ struct efx_nic *efx;
+ int i, rc;
+
+ /* Allocate and initialise a struct net_device and struct efx_nic */
+ net_dev = alloc_etherdev(sizeof(*efx));
+ if (!net_dev)
+ return -ENOMEM;
+ net_dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
+ if (lro)
+ net_dev->features |= NETIF_F_LRO;
+ efx = net_dev->priv;
+ pci_set_drvdata(pci_dev, efx);
+ rc = efx_init_struct(efx, type, pci_dev, net_dev);
+ if (rc)
+ goto fail1;
+
+ EFX_INFO(efx, "Solarflare Communications NIC detected\n");
+
+ /* Set up basic I/O (BAR mappings etc) */
+ rc = efx_init_io(efx);
+ if (rc)
+ goto fail2;
+
+ /* No serialisation is required with the reset path because
+ * we're in STATE_INIT. */
+ for (i = 0; i < 5; i++) {
+ rc = efx_pci_probe_main(efx);
+ if (rc == 0)
+ break;
+
+ /* Serialise against efx_reset(). No more resets will be
+ * scheduled since efx_stop_all() has been called, and we
+ * have not and never have been registered with either
+ * the rtnetlink or driverlink layers. */
+ cancel_work_sync(&efx->reset_work);
+
+ /* Retry if a recoverably reset event has been scheduled */
+ if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
+ (efx->reset_pending != RESET_TYPE_ALL))
+ goto fail3;
+
+ efx->reset_pending = RESET_TYPE_NONE;
+ }
+
+ if (rc) {
+ EFX_ERR(efx, "Could not reset NIC\n");
+ goto fail4;
+ }
+
+ /* Switch to the running state before we expose the device to
+ * the OS. This is to ensure that the initial gathering of
+ * MAC stats succeeds. */
+ rtnl_lock();
+ efx->state = STATE_RUNNING;
+ rtnl_unlock();
+
+ rc = efx_register_netdev(efx);
+ if (rc)
+ goto fail5;
+
+ EFX_LOG(efx, "initialisation successful\n");
+
+ return 0;
+
+ fail5:
+ efx_pci_remove_main(efx);
+ fail4:
+ fail3:
+ efx_fini_io(efx);
+ fail2:
+ efx_fini_struct(efx);
+ fail1:
+ EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+ free_netdev(net_dev);
+ return rc;
+}
+
+static struct pci_driver efx_pci_driver = {
+ .name = EFX_DRIVER_NAME,
+ .id_table = efx_pci_table,
+ .probe = efx_pci_probe,
+ .remove = efx_pci_remove,
+};
+
+/**************************************************************************
+ *
+ * Kernel module interface
+ *
+ *************************************************************************/
+
+module_param(interrupt_mode, uint, 0444);
+MODULE_PARM_DESC(interrupt_mode,
+ "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
+
+static int __init efx_init_module(void)
+{
+ int rc;
+
+ printk(KERN_INFO "Solarflare NET driver v" EFX_DRIVER_VERSION "\n");
+
+ rc = register_netdevice_notifier(&efx_netdev_notifier);
+ if (rc)
+ goto err_notifier;
+
+ refill_workqueue = create_workqueue("sfc_refill");
+ if (!refill_workqueue) {
+ rc = -ENOMEM;
+ goto err_refill;
+ }
+
+ rc = pci_register_driver(&efx_pci_driver);
+ if (rc < 0)
+ goto err_pci;
+
+ return 0;
+
+ err_pci:
+ destroy_workqueue(refill_workqueue);
+ err_refill:
+ unregister_netdevice_notifier(&efx_netdev_notifier);
+ err_notifier:
+ return rc;
+}
+
+static void __exit efx_exit_module(void)
+{
+ printk(KERN_INFO "Solarflare NET driver unloading\n");
+
+ pci_unregister_driver(&efx_pci_driver);
+ destroy_workqueue(refill_workqueue);
+ unregister_netdevice_notifier(&efx_netdev_notifier);
+
+}
+
+module_init(efx_init_module);
+module_exit(efx_exit_module);
+
+MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
+ "Solarflare Communications");
+MODULE_DESCRIPTION("Solarflare Communications network driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, efx_pci_table);
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
new file mode 100644
index 00000000000..3b2f69f4a9a
--- /dev/null
+++ b/drivers/net/sfc/efx.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_EFX_H
+#define EFX_EFX_H
+
+#include "net_driver.h"
+
+/* PCI IDs */
+#define EFX_VENDID_SFC 0x1924
+#define FALCON_A_P_DEVID 0x0703
+#define FALCON_A_S_DEVID 0x6703
+#define FALCON_B_P_DEVID 0x0710
+
+/* TX */
+extern int efx_xmit(struct efx_nic *efx,
+ struct efx_tx_queue *tx_queue, struct sk_buff *skb);
+extern void efx_stop_queue(struct efx_nic *efx);
+extern void efx_wake_queue(struct efx_nic *efx);
+
+/* RX */
+extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
+extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+ unsigned int len, int checksummed, int discard);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+
+/* Channels */
+extern void efx_process_channel_now(struct efx_channel *channel);
+extern int efx_flush_queues(struct efx_nic *efx);
+
+/* Ports */
+extern void efx_reconfigure_port(struct efx_nic *efx);
+
+/* Global */
+extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
+extern void efx_suspend(struct efx_nic *efx);
+extern void efx_resume(struct efx_nic *efx);
+extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
+ int rx_usecs);
+extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
+extern void efx_hex_dump(const u8 *, unsigned int, const char *);
+
+/* Dummy PHY ops for PHY drivers */
+extern int efx_port_dummy_op_int(struct efx_nic *efx);
+extern void efx_port_dummy_op_void(struct efx_nic *efx);
+extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
+
+
+extern unsigned int efx_monitor_interval;
+
+static inline void efx_schedule_channel(struct efx_channel *channel)
+{
+ EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
+ channel->channel, raw_smp_processor_id());
+ channel->work_pending = 1;
+
+ netif_rx_schedule(channel->napi_dev, &channel->napi_str);
+}
+
+#endif /* EFX_EFX_H */
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
new file mode 100644
index 00000000000..43663a4619d
--- /dev/null
+++ b/drivers/net/sfc/enum.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_ENUM_H
+#define EFX_ENUM_H
+
+/*****************************************************************************/
+
+/**
+ * enum reset_type - reset types
+ *
+ * %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
+ * %RESET_TYPE_DISABLE specify the method/scope of the reset. The
+ * other valuesspecify reasons, which efx_schedule_reset() will choose
+ * a method for.
+ *
+ * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
+ * @RESET_TYPE_ALL: reset everything but PCI core blocks
+ * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
+ * @RESET_TYPE_DISABLE: disable NIC
+ * @RESET_TYPE_MONITOR: reset due to hardware monitor
+ * @RESET_TYPE_INT_ERROR: reset due to internal error
+ * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
+ * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
+ * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
+ * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
+ */
+enum reset_type {
+ RESET_TYPE_NONE = -1,
+ RESET_TYPE_INVISIBLE = 0,
+ RESET_TYPE_ALL = 1,
+ RESET_TYPE_WORLD = 2,
+ RESET_TYPE_DISABLE = 3,
+ RESET_TYPE_MAX_METHOD,
+ RESET_TYPE_MONITOR,
+ RESET_TYPE_INT_ERROR,
+ RESET_TYPE_RX_RECOVERY,
+ RESET_TYPE_RX_DESC_FETCH,
+ RESET_TYPE_TX_DESC_FETCH,
+ RESET_TYPE_TX_SKIP,
+ RESET_TYPE_MAX,
+};
+
+#endif /* EFX_ENUM_H */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
new file mode 100644
index 00000000000..ad541badbd9
--- /dev/null
+++ b/drivers/net/sfc/ethtool.c
@@ -0,0 +1,460 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "ethtool.h"
+#include "falcon.h"
+#include "gmii.h"
+#include "mac.h"
+
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
+
+struct ethtool_string {
+ char name[ETH_GSTRING_LEN];
+};
+
+struct efx_ethtool_stat {
+ const char *name;
+ enum {
+ EFX_ETHTOOL_STAT_SOURCE_mac_stats,
+ EFX_ETHTOOL_STAT_SOURCE_nic,
+ EFX_ETHTOOL_STAT_SOURCE_channel
+ } source;
+ unsigned offset;
+ u64(*get_stat) (void *field); /* Reader function */
+};
+
+/* Initialiser for a struct #efx_ethtool_stat with type-checking */
+#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
+ get_stat_function) { \
+ .name = #stat_name, \
+ .source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \
+ .offset = ((((field_type *) 0) == \
+ &((struct efx_##source_name *)0)->field) ? \
+ offsetof(struct efx_##source_name, field) : \
+ offsetof(struct efx_##source_name, field)), \
+ .get_stat = get_stat_function, \
+}
+
+static u64 efx_get_uint_stat(void *field)
+{
+ return *(unsigned int *)field;
+}
+
+static u64 efx_get_ulong_stat(void *field)
+{
+ return *(unsigned long *)field;
+}
+
+static u64 efx_get_u64_stat(void *field)
+{
+ return *(u64 *) field;
+}
+
+static u64 efx_get_atomic_stat(void *field)
+{
+ return atomic_read((atomic_t *) field);
+}
+
+#define EFX_ETHTOOL_ULONG_MAC_STAT(field) \
+ EFX_ETHTOOL_STAT(field, mac_stats, field, \
+ unsigned long, efx_get_ulong_stat)
+
+#define EFX_ETHTOOL_U64_MAC_STAT(field) \
+ EFX_ETHTOOL_STAT(field, mac_stats, field, \
+ u64, efx_get_u64_stat)
+
+#define EFX_ETHTOOL_UINT_NIC_STAT(name) \
+ EFX_ETHTOOL_STAT(name, nic, n_##name, \
+ unsigned int, efx_get_uint_stat)
+
+#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \
+ EFX_ETHTOOL_STAT(field, nic, field, \
+ atomic_t, efx_get_atomic_stat)
+
+#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \
+ EFX_ETHTOOL_STAT(field, channel, n_##field, \
+ unsigned int, efx_get_uint_stat)
+
+static struct efx_ethtool_stat efx_ethtool_stats[] = {
+ EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_control),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_good),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_control),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error),
+ EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
+ EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
+};
+
+/* Number of ethtool statistics */
+#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
+
+/**************************************************************************
+ *
+ * Ethtool operations
+ *
+ **************************************************************************
+ */
+
+/* Identify device by flashing LEDs */
+static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ efx->board_info.blink(efx, 1);
+ schedule_timeout_interruptible(seconds * HZ);
+ efx->board_info.blink(efx, 0);
+ return 0;
+}
+
+/* This must be called with rtnl_lock held. */
+int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_get_settings(efx, ecmd);
+ mutex_unlock(&efx->mac_lock);
+
+ return rc;
+}
+
+/* This must be called with rtnl_lock held. */
+int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_set_settings(efx, ecmd);
+ mutex_unlock(&efx->mac_lock);
+ if (!rc)
+ efx_reconfigure_port(efx);
+
+ return rc;
+}
+
+static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *info)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
+}
+
+static int efx_ethtool_get_stats_count(struct net_device *net_dev)
+{
+ return EFX_ETHTOOL_NUM_STATS;
+}
+
+static void efx_ethtool_get_strings(struct net_device *net_dev,
+ u32 string_set, u8 *strings)
+{
+ struct ethtool_string *ethtool_strings =
+ (struct ethtool_string *)strings;
+ int i;
+
+ if (string_set == ETH_SS_STATS)
+ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
+ strncpy(ethtool_strings[i].name,
+ efx_ethtool_stats[i].name,
+ sizeof(ethtool_strings[i].name));
+}
+
+static void efx_ethtool_get_stats(struct net_device *net_dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ struct efx_ethtool_stat *stat;
+ struct efx_channel *channel;
+ int i;
+
+ EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
+
+ /* Update MAC and NIC statistics */
+ net_dev->get_stats(net_dev);
+
+ /* Fill detailed statistics buffer */
+ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
+ stat = &efx_ethtool_stats[i];
+ switch (stat->source) {
+ case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
+ data[i] = stat->get_stat((void *)mac_stats +
+ stat->offset);
+ break;
+ case EFX_ETHTOOL_STAT_SOURCE_nic:
+ data[i] = stat->get_stat((void *)efx + stat->offset);
+ break;
+ case EFX_ETHTOOL_STAT_SOURCE_channel:
+ data[i] = 0;
+ efx_for_each_channel(channel, efx)
+ data[i] += stat->get_stat((void *)channel +
+ stat->offset);
+ break;
+ }
+ }
+}
+
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ rc = ethtool_op_set_tx_csum(net_dev, enable);
+ if (rc)
+ return rc;
+
+ efx_flush_queues(efx);
+
+ return 0;
+}
+
+static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ /* No way to stop the hardware doing the checks; we just
+ * ignore the result.
+ */
+ efx->rx_checksum_enabled = (enable ? 1 : 0);
+
+ return 0;
+}
+
+static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx->rx_checksum_enabled;
+}
+
+/* Restart autonegotiation */
+static int efx_ethtool_nway_reset(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return mii_nway_restart(&efx->mii);
+}
+
+static u32 efx_ethtool_get_link(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx->link_up;
+}
+
+static int efx_ethtool_get_coalesce(struct net_device *net_dev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+
+ memset(coalesce, 0, sizeof(*coalesce));
+
+ /* Find lowest IRQ moderation across all used TX queues */
+ coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
+ efx_for_each_tx_queue(tx_queue, efx) {
+ channel = tx_queue->channel;
+ if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
+ if (channel->used_flags != EFX_USED_BY_RX_TX)
+ coalesce->tx_coalesce_usecs_irq =
+ channel->irq_moderation;
+ else
+ coalesce->tx_coalesce_usecs_irq = 0;
+ }
+ }
+
+ /* Find lowest IRQ moderation across all used RX queues */
+ coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
+ efx_for_each_rx_queue(rx_queue, efx) {
+ channel = rx_queue->channel;
+ if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
+ coalesce->rx_coalesce_usecs_irq =
+ channel->irq_moderation;
+ }
+
+ return 0;
+}
+
+/* Set coalescing parameters
+ * The difficulties occur for shared channels
+ */
+static int efx_ethtool_set_coalesce(struct net_device *net_dev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ unsigned tx_usecs, rx_usecs;
+
+ if (coalesce->use_adaptive_rx_coalesce ||
+ coalesce->use_adaptive_tx_coalesce)
+ return -EOPNOTSUPP;
+
+ if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
+ EFX_ERR(efx, "invalid coalescing setting. "
+ "Only rx/tx_coalesce_usecs_irq are supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ rx_usecs = coalesce->rx_coalesce_usecs_irq;
+ tx_usecs = coalesce->tx_coalesce_usecs_irq;
+
+ /* If the channel is shared only allow RX parameters to be set */
+ efx_for_each_tx_queue(tx_queue, efx) {
+ if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
+ tx_usecs) {
+ EFX_ERR(efx, "Channel is shared. "
+ "Only RX coalescing may be set\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
+
+ /* Reset channel to pick up new moderation value. Note that
+ * this may change the value of the irq_moderation field
+ * (e.g. to allow for hardware timer granularity).
+ */
+ efx_for_each_channel(channel, efx)
+ falcon_set_int_moderation(channel);
+
+ return 0;
+}
+
+static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct efx_nic *efx = net_dev->priv;
+ enum efx_fc_type flow_control = efx->flow_control;
+ int rc;
+
+ flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
+ flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
+ flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
+ flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
+
+ /* Try to push the pause parameters */
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_set_pause(efx, flow_control);
+ mutex_unlock(&efx->mac_lock);
+
+ if (!rc)
+ efx_reconfigure_port(efx);
+
+ return rc;
+}
+
+static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+ pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+ pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
+}
+
+
+struct ethtool_ops efx_ethtool_ops = {
+ .get_settings = efx_ethtool_get_settings,
+ .set_settings = efx_ethtool_set_settings,
+ .get_drvinfo = efx_ethtool_get_drvinfo,
+ .nway_reset = efx_ethtool_nway_reset,
+ .get_link = efx_ethtool_get_link,
+ .get_coalesce = efx_ethtool_get_coalesce,
+ .set_coalesce = efx_ethtool_set_coalesce,
+ .get_pauseparam = efx_ethtool_get_pauseparam,
+ .set_pauseparam = efx_ethtool_set_pauseparam,
+ .get_rx_csum = efx_ethtool_get_rx_csum,
+ .set_rx_csum = efx_ethtool_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = efx_ethtool_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
+ .get_strings = efx_ethtool_get_strings,
+ .phys_id = efx_ethtool_phys_id,
+ .get_stats_count = efx_ethtool_get_stats_count,
+ .get_ethtool_stats = efx_ethtool_get_stats,
+};
diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h
new file mode 100644
index 00000000000..3628e43df14
--- /dev/null
+++ b/drivers/net/sfc/ethtool.h
@@ -0,0 +1,27 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_ETHTOOL_H
+#define EFX_ETHTOOL_H
+
+#include "net_driver.h"
+
+/*
+ * Ethtool support
+ */
+
+extern int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd);
+extern int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd);
+
+extern struct ethtool_ops efx_ethtool_ops;
+
+#endif /* EFX_ETHTOOL_H */
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
new file mode 100644
index 00000000000..46db549ce58
--- /dev/null
+++ b/drivers/net/sfc/falcon.c
@@ -0,0 +1,2722 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include "net_driver.h"
+#include "bitfield.h"
+#include "efx.h"
+#include "mac.h"
+#include "gmii.h"
+#include "spi.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "boards.h"
+#include "workarounds.h"
+
+/* Falcon hardware control.
+ * Falcon is the internal codename for the SFC4000 controller that is
+ * present in SFE400X evaluation boards
+ */
+
+/**
+ * struct falcon_nic_data - Falcon NIC state
+ * @next_buffer_table: First available buffer table id
+ * @pci_dev2: The secondary PCI device if present
+ */
+struct falcon_nic_data {
+ unsigned next_buffer_table;
+ struct pci_dev *pci_dev2;
+};
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ **************************************************************************
+ */
+
+static int disable_dma_stats;
+
+/* This is set to 16 for a good reason. In summary, if larger than
+ * 16, the descriptor cache holds more than a default socket
+ * buffer's worth of packets (for UDP we can only have at most one
+ * socket buffer's worth outstanding). This combined with the fact
+ * that we only get 1 TX event per descriptor cache means the NIC
+ * goes idle.
+ */
+#define TX_DC_ENTRIES 16
+#define TX_DC_ENTRIES_ORDER 0
+#define TX_DC_BASE 0x130000
+
+#define RX_DC_ENTRIES 64
+#define RX_DC_ENTRIES_ORDER 2
+#define RX_DC_BASE 0x100000
+
+/* RX FIFO XOFF watermark
+ *
+ * When the amount of the RX FIFO increases used increases past this
+ * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
+ * This also has an effect on RX/TX arbitration
+ */
+static int rx_xoff_thresh_bytes = -1;
+module_param(rx_xoff_thresh_bytes, int, 0644);
+MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
+
+/* RX FIFO XON watermark
+ *
+ * When the amount of the RX FIFO used decreases below this
+ * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
+ * This also has an effect on RX/TX arbitration
+ */
+static int rx_xon_thresh_bytes = -1;
+module_param(rx_xon_thresh_bytes, int, 0644);
+MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
+
+/* TX descriptor ring size - min 512 max 4k */
+#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K
+#define FALCON_TXD_RING_SIZE 1024
+#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1)
+
+/* RX descriptor ring size - min 512 max 4k */
+#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K
+#define FALCON_RXD_RING_SIZE 1024
+#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1)
+
+/* Event queue size - max 32k */
+#define FALCON_EVQ_ORDER EVQ_SIZE_4K
+#define FALCON_EVQ_SIZE 4096
+#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
+
+/* Max number of internal errors. After this resets will not be performed */
+#define FALCON_MAX_INT_ERRORS 4
+
+/* Maximum period that we wait for flush events. If the flush event
+ * doesn't arrive in this period of time then we check if the queue
+ * was disabled anyway. */
+#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */
+
+/**************************************************************************
+ *
+ * Falcon constants
+ *
+ **************************************************************************
+ */
+
+/* DMA address mask (up to 46-bit, avoiding compiler warnings)
+ *
+ * Note that it is possible to have a platform with 64-bit longs and
+ * 32-bit DMA addresses, or vice versa. EFX_DMA_MASK takes care of the
+ * platform DMA mask.
+ */
+#if BITS_PER_LONG == 64
+#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL)
+#else
+#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL)
+#endif
+
+/* TX DMA length mask (13-bit) */
+#define FALCON_TX_DMA_MASK (4096 - 1)
+
+/* Size and alignment of special buffers (4KB) */
+#define FALCON_BUF_SIZE 4096
+
+/* Dummy SRAM size code */
+#define SRM_NB_BSZ_ONCHIP_ONLY (-1)
+
+/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
+#define PCI_EXP_DEVCAP_PWR_VAL_LBN 18
+#define PCI_EXP_DEVCAP_PWR_SCL_LBN 26
+#define PCI_EXP_DEVCTL_PAYLOAD_LBN 5
+#define PCI_EXP_LNKSTA_LNK_WID 0x3f0
+#define PCI_EXP_LNKSTA_LNK_WID_LBN 4
+
+#define FALCON_IS_DUAL_FUNC(efx) \
+ (FALCON_REV(efx) < FALCON_REV_B0)
+
+/**************************************************************************
+ *
+ * Falcon hardware access
+ *
+ **************************************************************************/
+
+/* Read the current event from the event queue */
+static inline efx_qword_t *falcon_event(struct efx_channel *channel,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (channel->eventq.addr)) + index);
+}
+
+/* See if an event is present
+ *
+ * We check both the high and low dword of the event for all ones. We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords. This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int falcon_event_present(efx_qword_t *event)
+{
+ return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
+ EFX_DWORD_IS_ALL_ONES(event->dword[1])));
+}
+
+/**************************************************************************
+ *
+ * I2C bus - this is a bit-bashing interface using GPIO pins
+ * Note that it uses the output enables to tristate the outputs
+ * SDA is the data pin and SCL is the clock
+ *
+ **************************************************************************
+ */
+static void falcon_setsdascl(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
+ EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
+ falcon_write(i2c->efx, &reg, GPIO_CTL_REG_KER);
+}
+
+static int falcon_getsda(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+ return EFX_OWORD_FIELD(reg, GPIO3_IN);
+}
+
+static int falcon_getscl(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+ return EFX_DWORD_FIELD(reg, GPIO0_IN);
+}
+
+static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
+ .setsda = falcon_setsdascl,
+ .setscl = falcon_setsdascl,
+ .getsda = falcon_getsda,
+ .getscl = falcon_getscl,
+ .udelay = 100,
+ .mdelay = 10,
+};
+
+/**************************************************************************
+ *
+ * Falcon special buffer handling
+ * Special buffers are used for event queues and the TX and RX
+ * descriptor rings.
+ *
+ *************************************************************************/
+
+/*
+ * Initialise a Falcon special buffer
+ *
+ * This will define a buffer (previously allocated via
+ * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
+ * it to be used for event queues, descriptor rings etc.
+ */
+static int
+falcon_init_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ efx_qword_t buf_desc;
+ int index;
+ dma_addr_t dma_addr;
+ int i;
+
+ EFX_BUG_ON_PARANOID(!buffer->addr);
+
+ /* Write buffer descriptors to NIC */
+ for (i = 0; i < buffer->entries; i++) {
+ index = buffer->index + i;
+ dma_addr = buffer->dma_addr + (i * 4096);
+ EFX_LOG(efx, "mapping special buffer %d at %llx\n",
+ index, (unsigned long long)dma_addr);
+ EFX_POPULATE_QWORD_4(buf_desc,
+ IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K,
+ BUF_ADR_REGION, 0,
+ BUF_ADR_FBUF, (dma_addr >> 12),
+ BUF_OWNER_ID_FBUF, 0);
+ falcon_write_sram(efx, &buf_desc, index);
+ }
+
+ return 0;
+}
+
+/* Unmaps a buffer from Falcon and clears the buffer table entries */
+static void
+falcon_fini_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ efx_oword_t buf_tbl_upd;
+ unsigned int start = buffer->index;
+ unsigned int end = (buffer->index + buffer->entries - 1);
+
+ if (!buffer->entries)
+ return;
+
+ EFX_LOG(efx, "unmapping special buffers %d-%d\n",
+ buffer->index, buffer->index + buffer->entries - 1);
+
+ EFX_POPULATE_OWORD_4(buf_tbl_upd,
+ BUF_UPD_CMD, 0,
+ BUF_CLR_CMD, 1,
+ BUF_CLR_END_ID, end,
+ BUF_CLR_START_ID, start);
+ falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER);
+}
+
+/*
+ * Allocate a new Falcon special buffer
+ *
+ * This allocates memory for a new buffer, clears it and allocates a
+ * new buffer ID range. It does not write into Falcon's buffer table.
+ *
+ * This call will allocate 4KB buffers, since Falcon can't use 8KB
+ * buffers for event queues and descriptor rings.
+ */
+static int falcon_alloc_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer,
+ unsigned int len)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ len = ALIGN(len, FALCON_BUF_SIZE);
+
+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+ &buffer->dma_addr);
+ if (!buffer->addr)
+ return -ENOMEM;
+ buffer->len = len;
+ buffer->entries = len / FALCON_BUF_SIZE;
+ BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1));
+
+ /* All zeros is a potentially valid event so memset to 0xff */
+ memset(buffer->addr, 0xff, len);
+
+ /* Select new buffer ID */
+ buffer->index = nic_data->next_buffer_table;
+ nic_data->next_buffer_table += buffer->entries;
+
+ EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %lx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (unsigned long long)buffer->dma_addr, len,
+ buffer->addr, virt_to_phys(buffer->addr));
+
+ return 0;
+}
+
+static void falcon_free_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ if (!buffer->addr)
+ return;
+
+ EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %lx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (unsigned long long)buffer->dma_addr, buffer->len,
+ buffer->addr, virt_to_phys(buffer->addr));
+
+ pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
+ buffer->dma_addr);
+ buffer->addr = NULL;
+ buffer->entries = 0;
+}
+
+/**************************************************************************
+ *
+ * Falcon generic buffer handling
+ * These buffers are used for interrupt status and MAC stats
+ *
+ **************************************************************************/
+
+static int falcon_alloc_buffer(struct efx_nic *efx,
+ struct efx_buffer *buffer, unsigned int len)
+{
+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+ &buffer->dma_addr);
+ if (!buffer->addr)
+ return -ENOMEM;
+ buffer->len = len;
+ memset(buffer->addr, 0, len);
+ return 0;
+}
+
+static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
+{
+ if (buffer->addr) {
+ pci_free_consistent(efx->pci_dev, buffer->len,
+ buffer->addr, buffer->dma_addr);
+ buffer->addr = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * Falcon TX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified transmit descriptor in the TX
+ * descriptor queue belonging to the specified channel.
+ */
+static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
+}
+
+/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */
+static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
+{
+ unsigned write_ptr;
+ efx_dword_t reg;
+
+ write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
+ EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr);
+ falcon_writel_page(tx_queue->efx, &reg,
+ TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue);
+}
+
+
+/* For each entry inserted into the software descriptor ring, create a
+ * descriptor in the hardware TX descriptor ring (in host memory), and
+ * write a doorbell.
+ */
+void falcon_push_buffers(struct efx_tx_queue *tx_queue)
+{
+
+ struct efx_tx_buffer *buffer;
+ efx_qword_t *txd;
+ unsigned write_ptr;
+
+ BUG_ON(tx_queue->write_count == tx_queue->insert_count);
+
+ do {
+ write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
+ buffer = &tx_queue->buffer[write_ptr];
+ txd = falcon_tx_desc(tx_queue, write_ptr);
+ ++tx_queue->write_count;
+
+ /* Create TX descriptor ring entry */
+ EFX_POPULATE_QWORD_5(*txd,
+ TX_KER_PORT, 0,
+ TX_KER_CONT, buffer->continuation,
+ TX_KER_BYTE_CNT, buffer->len,
+ TX_KER_BUF_REGION, 0,
+ TX_KER_BUF_ADR, buffer->dma_addr);
+ } while (tx_queue->write_count != tx_queue->insert_count);
+
+ wmb(); /* Ensure descriptors are written before they are fetched */
+ falcon_notify_tx_desc(tx_queue);
+}
+
+/* Allocate hardware resources for a TX queue */
+int falcon_probe_tx(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ return falcon_alloc_special_buffer(efx, &tx_queue->txd,
+ FALCON_TXD_RING_SIZE *
+ sizeof(efx_qword_t));
+}
+
+int falcon_init_tx(struct efx_tx_queue *tx_queue)
+{
+ efx_oword_t tx_desc_ptr;
+ struct efx_nic *efx = tx_queue->efx;
+ int rc;
+
+ /* Pin TX descriptor ring */
+ rc = falcon_init_special_buffer(efx, &tx_queue->txd);
+ if (rc)
+ return rc;
+
+ /* Push TX descriptor ring to card */
+ EFX_POPULATE_OWORD_10(tx_desc_ptr,
+ TX_DESCQ_EN, 1,
+ TX_ISCSI_DDIG_EN, 0,
+ TX_ISCSI_HDIG_EN, 0,
+ TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
+ TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum,
+ TX_DESCQ_OWNER_ID, 0,
+ TX_DESCQ_LABEL, tx_queue->queue,
+ TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
+ TX_DESCQ_TYPE, 0,
+ TX_NON_IP_DROP_DIS_B0, 1);
+
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
+ }
+
+ falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+
+ if (FALCON_REV(efx) < FALCON_REV_B0) {
+ efx_oword_t reg;
+
+ BUG_ON(tx_queue->queue >= 128); /* HW limit */
+
+ falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
+ if (efx->net_dev->features & NETIF_F_IP_CSUM)
+ clear_bit_le(tx_queue->queue, (void *)&reg);
+ else
+ set_bit_le(tx_queue->queue, (void *)&reg);
+ falcon_write(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
+ }
+
+ return 0;
+}
+
+static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct efx_channel *channel = &efx->channel[0];
+ efx_oword_t tx_flush_descq;
+ unsigned int read_ptr, i;
+
+ /* Post a flush command */
+ EFX_POPULATE_OWORD_2(tx_flush_descq,
+ TX_FLUSH_DESCQ_CMD, 1,
+ TX_FLUSH_DESCQ, tx_queue->queue);
+ falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
+ msleep(FALCON_FLUSH_TIMEOUT);
+
+ if (EFX_WORKAROUND_7803(efx))
+ return 0;
+
+ /* Look for a flush completed event */
+ read_ptr = channel->eventq_read_ptr;
+ for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+ efx_qword_t *event = falcon_event(channel, read_ptr);
+ int ev_code, ev_sub_code, ev_queue;
+ if (!falcon_event_present(event))
+ break;
+
+ ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID);
+ if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) &&
+ (ev_queue == tx_queue->queue)) {
+ EFX_LOG(efx, "tx queue %d flush command succesful\n",
+ tx_queue->queue);
+ return 0;
+ }
+
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ }
+
+ if (EFX_WORKAROUND_11557(efx)) {
+ efx_oword_t reg;
+ int enabled;
+
+ falcon_read_table(efx, &reg, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+ enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN);
+ if (!enabled) {
+ EFX_LOG(efx, "tx queue %d disabled without a "
+ "flush event seen\n", tx_queue->queue);
+ return 0;
+ }
+ }
+
+ EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
+ return -ETIMEDOUT;
+}
+
+void falcon_fini_tx(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ efx_oword_t tx_desc_ptr;
+
+ /* Stop the hardware using the queue */
+ if (falcon_flush_tx_queue(tx_queue))
+ EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue);
+
+ /* Remove TX descriptor ring from card */
+ EFX_ZERO_OWORD(tx_desc_ptr);
+ falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+
+ /* Unpin TX descriptor ring */
+ falcon_fini_special_buffer(efx, &tx_queue->txd);
+}
+
+/* Free buffers backing TX queue */
+void falcon_remove_tx(struct efx_tx_queue *tx_queue)
+{
+ falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd);
+}
+
+/**************************************************************************
+ *
+ * Falcon RX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified descriptor in the RX descriptor queue */
+static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
+}
+
+/* This creates an entry in the RX descriptor queue */
+static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
+ unsigned index)
+{
+ struct efx_rx_buffer *rx_buf;
+ efx_qword_t *rxd;
+
+ rxd = falcon_rx_desc(rx_queue, index);
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ EFX_POPULATE_QWORD_3(*rxd,
+ RX_KER_BUF_SIZE,
+ rx_buf->len -
+ rx_queue->efx->type->rx_buffer_padding,
+ RX_KER_BUF_REGION, 0,
+ RX_KER_BUF_ADR, rx_buf->dma_addr);
+}
+
+/* This writes to the RX_DESC_WPTR register for the specified receive
+ * descriptor ring.
+ */
+void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
+{
+ efx_dword_t reg;
+ unsigned write_ptr;
+
+ while (rx_queue->notified_count != rx_queue->added_count) {
+ falcon_build_rx_desc(rx_queue,
+ rx_queue->notified_count &
+ FALCON_RXD_RING_MASK);
+ ++rx_queue->notified_count;
+ }
+
+ wmb();
+ write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK;
+ EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr);
+ falcon_writel_page(rx_queue->efx, &reg,
+ RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue);
+}
+
+int falcon_probe_rx(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ return falcon_alloc_special_buffer(efx, &rx_queue->rxd,
+ FALCON_RXD_RING_SIZE *
+ sizeof(efx_qword_t));
+}
+
+int falcon_init_rx(struct efx_rx_queue *rx_queue)
+{
+ efx_oword_t rx_desc_ptr;
+ struct efx_nic *efx = rx_queue->efx;
+ int rc;
+ int is_b0 = FALCON_REV(efx) >= FALCON_REV_B0;
+ int iscsi_digest_en = is_b0;
+
+ EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
+ rx_queue->queue, rx_queue->rxd.index,
+ rx_queue->rxd.index + rx_queue->rxd.entries - 1);
+
+ /* Pin RX descriptor ring */
+ rc = falcon_init_special_buffer(efx, &rx_queue->rxd);
+ if (rc)
+ return rc;
+
+ /* Push RX descriptor ring to card */
+ EFX_POPULATE_OWORD_10(rx_desc_ptr,
+ RX_ISCSI_DDIG_EN, iscsi_digest_en,
+ RX_ISCSI_HDIG_EN, iscsi_digest_en,
+ RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
+ RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum,
+ RX_DESCQ_OWNER_ID, 0,
+ RX_DESCQ_LABEL, rx_queue->queue,
+ RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
+ RX_DESCQ_TYPE, 0 /* kernel queue */ ,
+ /* For >=B0 this is scatter so disable */
+ RX_DESCQ_JUMBO, !is_b0,
+ RX_DESCQ_EN, 1);
+ falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+ return 0;
+}
+
+static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct efx_channel *channel = &efx->channel[0];
+ unsigned int read_ptr, i;
+ efx_oword_t rx_flush_descq;
+
+ /* Post a flush command */
+ EFX_POPULATE_OWORD_2(rx_flush_descq,
+ RX_FLUSH_DESCQ_CMD, 1,
+ RX_FLUSH_DESCQ, rx_queue->queue);
+ falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
+ msleep(FALCON_FLUSH_TIMEOUT);
+
+ if (EFX_WORKAROUND_7803(efx))
+ return 0;
+
+ /* Look for a flush completed event */
+ read_ptr = channel->eventq_read_ptr;
+ for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+ efx_qword_t *event = falcon_event(channel, read_ptr);
+ int ev_code, ev_sub_code, ev_queue, ev_failed;
+ if (!falcon_event_present(event))
+ break;
+
+ ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID);
+ ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL);
+
+ if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) &&
+ (ev_queue == rx_queue->queue)) {
+ if (ev_failed) {
+ EFX_INFO(efx, "rx queue %d flush command "
+ "failed\n", rx_queue->queue);
+ return -EAGAIN;
+ } else {
+ EFX_LOG(efx, "rx queue %d flush command "
+ "succesful\n", rx_queue->queue);
+ return 0;
+ }
+ }
+
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ }
+
+ if (EFX_WORKAROUND_11557(efx)) {
+ efx_oword_t reg;
+ int enabled;
+
+ falcon_read_table(efx, &reg, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+ enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN);
+ if (!enabled) {
+ EFX_LOG(efx, "rx queue %d disabled without a "
+ "flush event seen\n", rx_queue->queue);
+ return 0;
+ }
+ }
+
+ EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue);
+ return -ETIMEDOUT;
+}
+
+void falcon_fini_rx(struct efx_rx_queue *rx_queue)
+{
+ efx_oword_t rx_desc_ptr;
+ struct efx_nic *efx = rx_queue->efx;
+ int i, rc;
+
+ /* Try and flush the rx queue. This may need to be repeated */
+ for (i = 0; i < 5; i++) {
+ rc = falcon_flush_rx_queue(rx_queue);
+ if (rc == -EAGAIN)
+ continue;
+ break;
+ }
+ if (rc)
+ EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
+
+ /* Remove RX descriptor ring from card */
+ EFX_ZERO_OWORD(rx_desc_ptr);
+ falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+
+ /* Unpin RX descriptor ring */
+ falcon_fini_special_buffer(efx, &rx_queue->rxd);
+}
+
+/* Free buffers backing RX queue */
+void falcon_remove_rx(struct efx_rx_queue *rx_queue)
+{
+ falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
+}
+
+/**************************************************************************
+ *
+ * Falcon event queue processing
+ * Event queues are processed by per-channel tasklets.
+ *
+ **************************************************************************/
+
+/* Update a channel's event queue's read pointer (RPTR) register
+ *
+ * This writes the EVQ_RPTR_REG register for the specified channel's
+ * event queue.
+ *
+ * Note that EVQ_RPTR_REG contains the index of the "last read" event,
+ * whereas channel->eventq_read_ptr contains the index of the "next to
+ * read" event.
+ */
+void falcon_eventq_read_ack(struct efx_channel *channel)
+{
+ efx_dword_t reg;
+ struct efx_nic *efx = channel->efx;
+
+ EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
+ falcon_writel_table(efx, &reg, efx->type->evq_rptr_tbl_base,
+ channel->evqnum);
+}
+
+/* Use HW to insert a SW defined event */
+void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ efx_oword_t drv_ev_reg;
+
+ EFX_POPULATE_OWORD_2(drv_ev_reg,
+ DRV_EV_QID, channel->evqnum,
+ DRV_EV_DATA,
+ EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
+ falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
+}
+
+/* Handle a transmit completion event
+ *
+ * Falcon batches TX completion events; the message we receive is of
+ * the form "complete all TX events up to this index".
+ */
+static inline void falcon_handle_tx_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ unsigned int tx_ev_desc_ptr;
+ unsigned int tx_ev_q_label;
+ struct efx_tx_queue *tx_queue;
+ struct efx_nic *efx = channel->efx;
+
+ if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) {
+ /* Transmit completion */
+ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ tx_queue = &efx->tx_queue[tx_ev_q_label];
+ efx_xmit_done(tx_queue, tx_ev_desc_ptr);
+ } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
+ /* Rewrite the FIFO write pointer */
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ tx_queue = &efx->tx_queue[tx_ev_q_label];
+
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_lock(efx->net_dev);
+ falcon_notify_tx_desc(tx_queue);
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_unlock(efx->net_dev);
+ } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
+ EFX_WORKAROUND_10727(efx)) {
+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
+ } else {
+ EFX_ERR(efx, "channel %d unexpected TX event "
+ EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+ }
+}
+
+/* Check received packet's destination MAC address. */
+static int check_dest_mac(struct efx_rx_queue *rx_queue,
+ const efx_qword_t *event)
+{
+ struct efx_rx_buffer *rx_buf;
+ struct efx_nic *efx = rx_queue->efx;
+ int rx_ev_desc_ptr;
+ struct ethhdr *eh;
+
+ if (efx->promiscuous)
+ return 1;
+
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
+ rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
+ eh = (struct ethhdr *)rx_buf->data;
+ if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
+ return 0;
+ return 1;
+}
+
+/* Detect errors included in the rx_evt_pkt_ok bit. */
+static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
+ const efx_qword_t *event,
+ unsigned *rx_ev_pkt_ok,
+ int *discard, int byte_count)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+ unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
+ unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
+ unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
+ unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+ int snap, non_ip;
+
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC);
+ rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE);
+ rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
+ RX_EV_BUF_OWNER_ID_ERR);
+ rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR);
+ rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
+ RX_EV_IP_HDR_CHKSUM_ERR);
+ rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
+ RX_EV_TCP_UDP_CHKSUM_ERR);
+ rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
+ rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
+ rx_ev_drib_nib = ((FALCON_REV(efx) >= FALCON_REV_B0) ?
+ 0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
+ rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
+
+ /* Every error apart from tobe_disc and pause_frm */
+ rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
+ rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
+ rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
+
+ snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
+ (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
+ non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
+
+ /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
+ * length field of an LLC frame, which sets TOBE_DISC. We could set
+ * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
+ * protect the RX block).
+ *
+ * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
+ * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
+ * LLC can't encapsulate IP, so by definition
+ * these packets are NON_IP.
+ *
+ * Unicast mismatch will also cause TOBE_DISC, so the driver needs
+ * to check this.
+ */
+ if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
+ /* If all the other flags are zero then we can state the
+ * entire packet is ok, which will flag to the kernel not
+ * to recalculate checksums.
+ */
+ if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
+ *rx_ev_pkt_ok = 1;
+
+ rx_ev_tobe_disc = 0;
+
+ /* TOBE_DISC is set for unicast mismatch. But given that
+ * we can't trust TOBE_DISC here, we must validate the dest
+ * MAC address ourselves.
+ */
+ if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
+ rx_ev_tobe_disc = 1;
+ }
+
+ /* Count errors that are not in MAC stats. */
+ if (rx_ev_frm_trunc)
+ ++rx_queue->channel->n_rx_frm_trunc;
+ else if (rx_ev_tobe_disc)
+ ++rx_queue->channel->n_rx_tobe_disc;
+ else if (rx_ev_ip_hdr_chksum_err)
+ ++rx_queue->channel->n_rx_ip_hdr_chksum_err;
+ else if (rx_ev_tcp_udp_chksum_err)
+ ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
+ if (rx_ev_ip_frag_err)
+ ++rx_queue->channel->n_rx_ip_frag_err;
+
+ /* The frame must be discarded if any of these are true. */
+ *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
+ rx_ev_tobe_disc | rx_ev_pause_frm);
+
+ /* TOBE_DISC is expected on unicast mismatches; don't print out an
+ * error message. FRM_TRUNC indicates RXDP dropped the packet due
+ * to a FIFO overflow.
+ */
+#ifdef EFX_ENABLE_DEBUG
+ if (rx_ev_other_err) {
+ EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
+ EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
+ rx_queue->queue, EFX_QWORD_VAL(*event),
+ rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
+ rx_ev_ip_hdr_chksum_err ?
+ " [IP_HDR_CHKSUM_ERR]" : "",
+ rx_ev_tcp_udp_chksum_err ?
+ " [TCP_UDP_CHKSUM_ERR]" : "",
+ rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
+ rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
+ rx_ev_drib_nib ? " [DRIB_NIB]" : "",
+ rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
+ rx_ev_pause_frm ? " [PAUSE]" : "",
+ snap ? " [SNAP/LLC]" : "");
+ }
+#endif
+
+ if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) &&
+ efx->phy_type == PHY_TYPE_10XPRESS))
+ tenxpress_crc_err(efx);
+}
+
+/* Handle receive events that are not in-order. */
+static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
+ unsigned index)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned expected, dropped;
+
+ expected = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ dropped = ((index + FALCON_RXD_RING_SIZE - expected) &
+ FALCON_RXD_RING_MASK);
+ EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
+ dropped, index, expected);
+
+ efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+}
+
+/* Handle a packet received event
+ *
+ * Falcon silicon gives a "discard" flag if it's a unicast packet with the
+ * wrong destination address
+ * Also "is multicast" and "matches multicast filter" flags can be used to
+ * discard non-matching multicast packets.
+ */
+static inline int falcon_handle_rx_event(struct efx_channel *channel,
+ const efx_qword_t *event)
+{
+ unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
+ unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
+ unsigned expected_ptr;
+ int discard = 0, checksummed;
+ struct efx_rx_queue *rx_queue;
+ struct efx_nic *efx = channel->efx;
+
+ /* Basic packet information */
+ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT);
+ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK);
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
+ WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
+ WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
+
+ rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL);
+ rx_queue = &efx->rx_queue[rx_ev_q_label];
+
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
+ expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ if (unlikely(rx_ev_desc_ptr != expected_ptr)) {
+ falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
+ return rx_ev_q_label;
+ }
+
+ if (likely(rx_ev_pkt_ok)) {
+ /* If packet is marked as OK and packet type is TCP/IPv4 or
+ * UDP/IPv4, then we can rely on the hardware checksum.
+ */
+ checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
+ } else {
+ falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
+ &discard, rx_ev_byte_cnt);
+ checksummed = 0;
+ }
+
+ /* Detect multicast packets that didn't match the filter */
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ if (rx_ev_mcast_pkt) {
+ unsigned int rx_ev_mcast_hash_match =
+ EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
+
+ if (unlikely(!rx_ev_mcast_hash_match))
+ discard = 1;
+ }
+
+ /* Handle received packet */
+ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
+ checksummed, discard);
+
+ return rx_ev_q_label;
+}
+
+/* Global events are basically PHY events */
+static void falcon_handle_global_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ int is_phy_event = 0, handled = 0;
+
+ /* Check for interrupt on either port. Some boards have a
+ * single PHY wired to the interrupt line for port 1. */
+ if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
+ EFX_QWORD_FIELD(*event, XG_PHY_INTR))
+ is_phy_event = 1;
+
+ if ((FALCON_REV(efx) >= FALCON_REV_B0) &&
+ EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
+ is_phy_event = 1;
+
+ if (is_phy_event) {
+ efx->phy_op->clear_interrupt(efx);
+ queue_work(efx->workqueue, &efx->reconfigure_work);
+ handled = 1;
+ }
+
+ if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
+ EFX_ERR(efx, "channel %d seen global RX_RESET "
+ "event. Resetting.\n", channel->channel);
+
+ atomic_inc(&efx->rx_reset);
+ efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+ handled = 1;
+ }
+
+ if (!handled)
+ EFX_ERR(efx, "channel %d unknown global event "
+ EFX_QWORD_FMT "\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+}
+
+static void falcon_handle_driver_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned int ev_sub_code;
+ unsigned int ev_sub_data;
+
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA);
+
+ switch (ev_sub_code) {
+ case TX_DESCQ_FLS_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
+ channel->channel, ev_sub_data);
+ break;
+ case RX_DESCQ_FLS_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
+ channel->channel, ev_sub_data);
+ break;
+ case EVQ_INIT_DONE_EV_DECODE:
+ EFX_LOG(efx, "channel %d EVQ %d initialised\n",
+ channel->channel, ev_sub_data);
+ break;
+ case SRM_UPD_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d SRAM update done\n",
+ channel->channel);
+ break;
+ case WAKE_UP_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
+ channel->channel, ev_sub_data);
+ break;
+ case TIMER_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
+ channel->channel, ev_sub_data);
+ break;
+ case RX_RECOVERY_EV_DECODE:
+ EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
+ "Resetting.\n", channel->channel);
+ efx_schedule_reset(efx,
+ EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY :
+ RESET_TYPE_DISABLE);
+ break;
+ case RX_DSC_ERROR_EV_DECODE:
+ EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
+ " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
+ break;
+ case TX_DSC_ERROR_EV_DECODE:
+ EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
+ " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
+ break;
+ default:
+ EFX_TRACE(efx, "channel %d unknown driver event code %d "
+ "data %04x\n", channel->channel, ev_sub_code,
+ ev_sub_data);
+ break;
+ }
+}
+
+int falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
+{
+ unsigned int read_ptr;
+ efx_qword_t event, *p_event;
+ int ev_code;
+ int rxq;
+ int rxdmaqs = 0;
+
+ read_ptr = channel->eventq_read_ptr;
+
+ do {
+ p_event = falcon_event(channel, read_ptr);
+ event = *p_event;
+
+ if (!falcon_event_present(&event))
+ /* End of events */
+ break;
+
+ EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
+ channel->channel, EFX_QWORD_VAL(event));
+
+ /* Clear this event by marking it all ones */
+ EFX_SET_QWORD(*p_event);
+
+ ev_code = EFX_QWORD_FIELD(event, EV_CODE);
+
+ switch (ev_code) {
+ case RX_IP_EV_DECODE:
+ rxq = falcon_handle_rx_event(channel, &event);
+ rxdmaqs |= (1 << rxq);
+ (*rx_quota)--;
+ break;
+ case TX_IP_EV_DECODE:
+ falcon_handle_tx_event(channel, &event);
+ break;
+ case DRV_GEN_EV_DECODE:
+ channel->eventq_magic
+ = EFX_QWORD_FIELD(event, EVQ_MAGIC);
+ EFX_LOG(channel->efx, "channel %d received generated "
+ "event "EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(event));
+ break;
+ case GLOBAL_EV_DECODE:
+ falcon_handle_global_event(channel, &event);
+ break;
+ case DRIVER_EV_DECODE:
+ falcon_handle_driver_event(channel, &event);
+ break;
+ default:
+ EFX_ERR(channel->efx, "channel %d unknown event type %d"
+ " (data " EFX_QWORD_FMT ")\n", channel->channel,
+ ev_code, EFX_QWORD_VAL(event));
+ }
+
+ /* Increment read pointer */
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+
+ } while (*rx_quota);
+
+ channel->eventq_read_ptr = read_ptr;
+ return rxdmaqs;
+}
+
+void falcon_set_int_moderation(struct efx_channel *channel)
+{
+ efx_dword_t timer_cmd;
+ struct efx_nic *efx = channel->efx;
+
+ /* Set timer register */
+ if (channel->irq_moderation) {
+ /* Round to resolution supported by hardware. The value we
+ * program is based at 0. So actual interrupt moderation
+ * achieved is ((x + 1) * res).
+ */
+ unsigned int res = 5;
+ channel->irq_moderation -= (channel->irq_moderation % res);
+ if (channel->irq_moderation < res)
+ channel->irq_moderation = res;
+ EFX_POPULATE_DWORD_2(timer_cmd,
+ TIMER_MODE, TIMER_MODE_INT_HLDOFF,
+ TIMER_VAL,
+ (channel->irq_moderation / res) - 1);
+ } else {
+ EFX_POPULATE_DWORD_2(timer_cmd,
+ TIMER_MODE, TIMER_MODE_DIS,
+ TIMER_VAL, 0);
+ }
+ falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
+ channel->evqnum);
+
+}
+
+/* Allocate buffer table entries for event queue */
+int falcon_probe_eventq(struct efx_channel *channel)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned int evq_size;
+
+ evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t);
+ return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
+}
+
+int falcon_init_eventq(struct efx_channel *channel)
+{
+ efx_oword_t evq_ptr;
+ struct efx_nic *efx = channel->efx;
+ int rc;
+
+ EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
+ channel->channel, channel->eventq.index,
+ channel->eventq.index + channel->eventq.entries - 1);
+
+ /* Pin event queue buffer */
+ rc = falcon_init_special_buffer(efx, &channel->eventq);
+ if (rc)
+ return rc;
+
+ /* Fill event queue with all ones (i.e. empty events) */
+ memset(channel->eventq.addr, 0xff, channel->eventq.len);
+
+ /* Push event queue to card */
+ EFX_POPULATE_OWORD_3(evq_ptr,
+ EVQ_EN, 1,
+ EVQ_SIZE, FALCON_EVQ_ORDER,
+ EVQ_BUF_BASE_ID, channel->eventq.index);
+ falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->evqnum);
+
+ falcon_set_int_moderation(channel);
+
+ return 0;
+}
+
+void falcon_fini_eventq(struct efx_channel *channel)
+{
+ efx_oword_t eventq_ptr;
+ struct efx_nic *efx = channel->efx;
+
+ /* Remove event queue from card */
+ EFX_ZERO_OWORD(eventq_ptr);
+ falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->evqnum);
+
+ /* Unpin event queue */
+ falcon_fini_special_buffer(efx, &channel->eventq);
+}
+
+/* Free buffers backing event queue */
+void falcon_remove_eventq(struct efx_channel *channel)
+{
+ falcon_free_special_buffer(channel->efx, &channel->eventq);
+}
+
+
+/* Generates a test event on the event queue. A subsequent call to
+ * process_eventq() should pick up the event and place the value of
+ * "magic" into channel->eventq_magic;
+ */
+void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
+{
+ efx_qword_t test_event;
+
+ EFX_POPULATE_QWORD_2(test_event,
+ EV_CODE, DRV_GEN_EV_DECODE,
+ EVQ_MAGIC, magic);
+ falcon_generate_event(channel, &test_event);
+}
+
+
+/**************************************************************************
+ *
+ * Falcon hardware interrupts
+ * The hardware interrupt handler does very little work; all the event
+ * queue processing is carried out by per-channel tasklets.
+ *
+ **************************************************************************/
+
+/* Enable/disable/generate Falcon interrupts */
+static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
+ int force)
+{
+ efx_oword_t int_en_reg_ker;
+
+ EFX_POPULATE_OWORD_2(int_en_reg_ker,
+ KER_INT_KER, force,
+ DRV_INT_EN_KER, enabled);
+ falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER);
+}
+
+void falcon_enable_interrupts(struct efx_nic *efx)
+{
+ efx_oword_t int_adr_reg_ker;
+ struct efx_channel *channel;
+
+ EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
+ wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
+
+ /* Program address */
+ EFX_POPULATE_OWORD_2(int_adr_reg_ker,
+ NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx),
+ INT_ADR_KER, efx->irq_status.dma_addr);
+ falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER);
+
+ /* Enable interrupts */
+ falcon_interrupts(efx, 1, 0);
+
+ /* Force processing of all the channels to get the EVQ RPTRs up to
+ date */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ efx_schedule_channel(channel);
+}
+
+void falcon_disable_interrupts(struct efx_nic *efx)
+{
+ /* Disable interrupts */
+ falcon_interrupts(efx, 0, 0);
+}
+
+/* Generate a Falcon test interrupt
+ * Interrupt must already have been enabled, otherwise nasty things
+ * may happen.
+ */
+void falcon_generate_interrupt(struct efx_nic *efx)
+{
+ falcon_interrupts(efx, 1, 1);
+}
+
+/* Acknowledge a legacy interrupt from Falcon
+ *
+ * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
+ *
+ * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
+ * BIU. Interrupt acknowledge is read sensitive so must write instead
+ * (then read to ensure the BIU collector is flushed)
+ *
+ * NB most hardware supports MSI interrupts
+ */
+static inline void falcon_irq_ack_a1(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e);
+ falcon_writel(efx, &reg, INT_ACK_REG_KER_A1);
+ falcon_readl(efx, &reg, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1);
+}
+
+/* Process a fatal interrupt
+ * Disable bus mastering ASAP and schedule a reset
+ */
+static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ efx_oword_t fatal_intr;
+ int error, mem_perr;
+ static int n_int_errors;
+
+ falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
+ error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
+
+ EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
+ EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
+ EFX_OWORD_VAL(fatal_intr),
+ error ? "disabling bus mastering" : "no recognised error");
+ if (error == 0)
+ goto out;
+
+ /* If this is a memory parity error dump which blocks are offending */
+ mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER);
+ if (mem_perr) {
+ efx_oword_t reg;
+ falcon_read(efx, &reg, MEM_STAT_REG_KER);
+ EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
+ EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
+ }
+
+ /* Disable DMA bus mastering on both devices */
+ pci_disable_device(efx->pci_dev);
+ if (FALCON_IS_DUAL_FUNC(efx))
+ pci_disable_device(nic_data->pci_dev2);
+
+ if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
+ EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
+ efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
+ } else {
+ EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
+ "NIC will be disabled\n");
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+/* Handle a legacy interrupt from Falcon
+ * Acknowledges the interrupt and schedule event queue processing.
+ */
+static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
+{
+ struct efx_nic *efx = (struct efx_nic *)dev_id;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_channel *channel;
+ efx_dword_t reg;
+ u32 queues;
+ int syserr;
+
+ /* Read the ISR which also ACKs the interrupts */
+ falcon_readl(efx, &reg, INT_ISR0_B0);
+ queues = EFX_EXTRACT_DWORD(reg, 0, 31);
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ if (queues == 0)
+ return IRQ_NONE;
+
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+
+ /* Schedule processing of any interrupting queues */
+ channel = &efx->channel[0];
+ while (queues) {
+ if (queues & 0x01)
+ efx_schedule_channel(channel);
+ channel++;
+ queues >>= 1;
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
+{
+ struct efx_nic *efx = (struct efx_nic *)dev_id;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_channel *channel;
+ int syserr;
+ int queues;
+
+ /* Check to see if this is our interrupt. If it isn't, we
+ * exit without having touched the hardware.
+ */
+ if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
+ EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
+ raw_smp_processor_id());
+ return IRQ_NONE;
+ }
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ /* Determine interrupting queues, clear interrupt status
+ * register and acknowledge the device interrupt.
+ */
+ BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
+ queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
+ EFX_ZERO_OWORD(*int_ker);
+ wmb(); /* Ensure the vector is cleared before interrupt ack */
+ falcon_irq_ack_a1(efx);
+
+ /* Schedule processing of any interrupting queues */
+ channel = &efx->channel[0];
+ while (queues) {
+ if (queues & 0x01)
+ efx_schedule_channel(channel);
+ channel++;
+ queues >>= 1;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Handle an MSI interrupt from Falcon
+ *
+ * Handle an MSI hardware interrupt. This routine schedules event
+ * queue processing. No interrupt acknowledgement cycle is necessary.
+ * Also, we never need to check that the interrupt is for us, since
+ * MSI interrupts cannot be shared.
+ */
+static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
+{
+ struct efx_channel *channel = (struct efx_channel *)dev_id;
+ struct efx_nic *efx = channel->efx;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ int syserr;
+
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ /* Schedule processing of the channel */
+ efx_schedule_channel(channel);
+
+ return IRQ_HANDLED;
+}
+
+
+/* Setup RSS indirection table.
+ * This maps from the hash value of the packet to RXQ
+ */
+static void falcon_setup_rss_indir_table(struct efx_nic *efx)
+{
+ int i = 0;
+ unsigned long offset;
+ efx_dword_t dword;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ for (offset = RX_RSS_INDIR_TBL_B0;
+ offset < RX_RSS_INDIR_TBL_B0 + 0x800;
+ offset += 0x10) {
+ EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
+ i % efx->rss_queues);
+ falcon_writel(efx, &dword, offset);
+ i++;
+ }
+}
+
+/* Hook interrupt handler(s)
+ * Try MSI and then legacy interrupts.
+ */
+int falcon_init_interrupt(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ if (!EFX_INT_MODE_USE_MSI(efx)) {
+ irq_handler_t handler;
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ handler = falcon_legacy_interrupt_b0;
+ else
+ handler = falcon_legacy_interrupt_a1;
+
+ rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
+ efx->name, efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
+ efx->pci_dev->irq);
+ goto fail1;
+ }
+ return 0;
+ }
+
+ /* Hook MSI or MSI-X interrupt */
+ efx_for_each_channel_with_interrupt(channel, efx) {
+ rc = request_irq(channel->irq, falcon_msi_interrupt,
+ IRQF_PROBE_SHARED, /* Not shared */
+ efx->name, channel);
+ if (rc) {
+ EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
+ goto fail2;
+ }
+ }
+
+ return 0;
+
+ fail2:
+ efx_for_each_channel_with_interrupt(channel, efx)
+ free_irq(channel->irq, channel);
+ fail1:
+ return rc;
+}
+
+void falcon_fini_interrupt(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ efx_oword_t reg;
+
+ /* Disable MSI/MSI-X interrupts */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ if (channel->irq)
+ free_irq(channel->irq, channel);
+
+ /* ACK legacy interrupt */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ falcon_read(efx, &reg, INT_ISR0_B0);
+ else
+ falcon_irq_ack_a1(efx);
+
+ /* Disable legacy interrupt */
+ if (efx->legacy_irq)
+ free_irq(efx->legacy_irq, efx);
+}
+
+/**************************************************************************
+ *
+ * EEPROM/flash
+ *
+ **************************************************************************
+ */
+
+#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
+
+/* Wait for SPI command completion */
+static int falcon_spi_wait(struct efx_nic *efx)
+{
+ efx_oword_t reg;
+ int cmd_en, timer_active;
+ int count;
+
+ count = 0;
+ do {
+ falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
+ cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
+ timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
+ if (!cmd_en && !timer_active)
+ return 0;
+ udelay(10);
+ } while (++count < 10000); /* wait upto 100msec */
+ EFX_ERR(efx, "timed out waiting for SPI\n");
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command,
+ unsigned int address, unsigned int addr_len,
+ void *data, unsigned int len)
+{
+ efx_oword_t reg;
+ int rc;
+
+ BUG_ON(len > FALCON_SPI_MAX_LEN);
+
+ /* Check SPI not currently being accessed */
+ rc = falcon_spi_wait(efx);
+ if (rc)
+ return rc;
+
+ /* Program address register */
+ EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
+ falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+
+ /* Issue read command */
+ EFX_POPULATE_OWORD_7(reg,
+ EE_SPI_HCMD_CMD_EN, 1,
+ EE_SPI_HCMD_SF_SEL, device_id,
+ EE_SPI_HCMD_DABCNT, len,
+ EE_SPI_HCMD_READ, EE_SPI_READ,
+ EE_SPI_HCMD_DUBCNT, 0,
+ EE_SPI_HCMD_ADBCNT, addr_len,
+ EE_SPI_HCMD_ENC, command);
+ falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
+
+ /* Wait for read to complete */
+ rc = falcon_spi_wait(efx);
+ if (rc)
+ return rc;
+
+ /* Read data */
+ falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
+ memcpy(data, &reg, len);
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * MAC wrapper
+ *
+ **************************************************************************
+ */
+void falcon_drain_tx_fifo(struct efx_nic *efx)
+{
+ efx_oword_t temp;
+ int count;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
+ /* There is no point in draining more than once */
+ if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ return;
+
+ /* MAC stats will fail whilst the TX fifo is draining. Serialise
+ * the drain sequence with the statistics fetch */
+ spin_lock(&efx->stats_lock);
+
+ EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
+ falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
+
+ /* Reset the MAC and EM block. */
+ falcon_read(efx, &temp, GLB_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
+ EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
+ EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
+ falcon_write(efx, &temp, GLB_CTL_REG_KER);
+
+ count = 0;
+ while (1) {
+ falcon_read(efx, &temp, GLB_CTL_REG_KER);
+ if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
+ !EFX_OWORD_FIELD(temp, RST_XGRX) &&
+ !EFX_OWORD_FIELD(temp, RST_EM)) {
+ EFX_LOG(efx, "Completed MAC reset after %d loops\n",
+ count);
+ break;
+ }
+ if (count > 20) {
+ EFX_ERR(efx, "MAC reset failed\n");
+ break;
+ }
+ count++;
+ udelay(10);
+ }
+
+ spin_unlock(&efx->stats_lock);
+
+ /* If we've reset the EM block and the link is up, then
+ * we'll have to kick the XAUI link so the PHY can recover */
+ if (efx->link_up && EFX_WORKAROUND_5147(efx))
+ falcon_reset_xaui(efx);
+}
+
+void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+{
+ efx_oword_t temp;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ /* Isolate the MAC -> RX */
+ falcon_read(efx, &temp, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
+ falcon_write(efx, &temp, RX_CFG_REG_KER);
+
+ if (!efx->link_up)
+ falcon_drain_tx_fifo(efx);
+}
+
+void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
+{
+ efx_oword_t reg;
+ int link_speed;
+ unsigned int tx_fc;
+
+ if (efx->link_options & GM_LPA_10000)
+ link_speed = 0x3;
+ else if (efx->link_options & GM_LPA_1000)
+ link_speed = 0x2;
+ else if (efx->link_options & GM_LPA_100)
+ link_speed = 0x1;
+ else
+ link_speed = 0x0;
+ /* MAC_LINK_STATUS controls MAC backpressure but doesn't work
+ * as advertised. Disable to ensure packets are not
+ * indefinitely held and TX queue can be flushed at any point
+ * while the link is down. */
+ EFX_POPULATE_OWORD_5(reg,
+ MAC_XOFF_VAL, 0xffff /* max pause time */,
+ MAC_BCAD_ACPT, 1,
+ MAC_UC_PROM, efx->promiscuous,
+ MAC_LINK_STATUS, 1, /* always set */
+ MAC_SPEED, link_speed);
+ /* On B0, MAC backpressure can be disabled and packets get
+ * discarded. */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
+ !efx->link_up);
+ }
+
+ falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
+
+ /* Restore the multicast hash registers. */
+ falcon_set_multicast_hash(efx);
+
+ /* Transmission of pause frames when RX crosses the threshold is
+ * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
+ * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
+ tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+ falcon_read(efx, &reg, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
+
+ /* Unisolate the MAC -> RX */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
+ falcon_write(efx, &reg, RX_CFG_REG_KER);
+}
+
+int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
+{
+ efx_oword_t reg;
+ u32 *dma_done;
+ int i;
+
+ if (disable_dma_stats)
+ return 0;
+
+ /* Statistics fetch will fail if the MAC is in TX drain */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ efx_oword_t temp;
+ falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
+ if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ return 0;
+ }
+
+ dma_done = (efx->stats_buffer.addr + done_offset);
+ *dma_done = FALCON_STATS_NOT_DONE;
+ wmb(); /* ensure done flag is clear */
+
+ /* Initiate DMA transfer of stats */
+ EFX_POPULATE_OWORD_2(reg,
+ MAC_STAT_DMA_CMD, 1,
+ MAC_STAT_DMA_ADR,
+ efx->stats_buffer.dma_addr);
+ falcon_write(efx, &reg, MAC0_STAT_DMA_REG_KER);
+
+ /* Wait for transfer to complete */
+ for (i = 0; i < 400; i++) {
+ if (*(volatile u32 *)dma_done == FALCON_STATS_DONE)
+ return 0;
+ udelay(10);
+ }
+
+ EFX_ERR(efx, "timed out waiting for statistics\n");
+ return -ETIMEDOUT;
+}
+
+/**************************************************************************
+ *
+ * PHY access via GMII
+ *
+ **************************************************************************
+ */
+
+/* Use the top bit of the MII PHY id to indicate the PHY type
+ * (1G/10G), with the remaining bits as the actual PHY id.
+ *
+ * This allows us to avoid leaking information from the mii_if_info
+ * structure into other data structures.
+ */
+#define FALCON_PHY_ID_ID_WIDTH EFX_WIDTH(MD_PRT_DEV_ADR)
+#define FALCON_PHY_ID_ID_MASK ((1 << FALCON_PHY_ID_ID_WIDTH) - 1)
+#define FALCON_PHY_ID_WIDTH (FALCON_PHY_ID_ID_WIDTH + 1)
+#define FALCON_PHY_ID_MASK ((1 << FALCON_PHY_ID_WIDTH) - 1)
+#define FALCON_PHY_ID_10G (1 << (FALCON_PHY_ID_WIDTH - 1))
+
+
+/* Packing the clause 45 port and device fields into a single value */
+#define MD_PRT_ADR_COMP_LBN (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN)
+#define MD_PRT_ADR_COMP_WIDTH MD_PRT_ADR_WIDTH
+#define MD_DEV_ADR_COMP_LBN 0
+#define MD_DEV_ADR_COMP_WIDTH MD_DEV_ADR_WIDTH
+
+
+/* Wait for GMII access to complete */
+static int falcon_gmii_wait(struct efx_nic *efx)
+{
+ efx_dword_t md_stat;
+ int count;
+
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
+ if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
+ if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
+ EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) {
+ EFX_ERR(efx, "error from GMII access "
+ EFX_DWORD_FMT"\n",
+ EFX_DWORD_VAL(md_stat));
+ return -EIO;
+ }
+ return 0;
+ }
+ udelay(10);
+ }
+ EFX_ERR(efx, "timed out waiting for GMII\n");
+ return -ETIMEDOUT;
+}
+
+/* Writes a GMII register of a PHY connected to Falcon using MDIO. */
+static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
+ int addr, int value)
+{
+ struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
+ efx_oword_t reg;
+
+ /* The 'generic' prt/dev packing in mdio_10g.h is conveniently
+ * chosen so that the only current user, Falcon, can take the
+ * packed value and use them directly.
+ * Fail to build if this assumption is broken.
+ */
+ BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G);
+ BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH);
+ BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN);
+ BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN);
+
+ if (phy_id2 == PHY_ADDR_INVALID)
+ return;
+
+ /* See falcon_mdio_read for an explanation. */
+ if (!(phy_id & FALCON_PHY_ID_10G)) {
+ int mmd = ffs(efx->phy_op->mmds) - 1;
+ EFX_TRACE(efx, "Fixing erroneous clause22 write\n");
+ phy_id2 = mdio_clause45_pack(phy_id2, mmd)
+ & FALCON_PHY_ID_ID_MASK;
+ }
+
+ EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id,
+ addr, value);
+
+ spin_lock_bh(&efx->phy_lock);
+
+ /* Check MII not currently being accessed */
+ if (falcon_gmii_wait(efx) != 0)
+ goto out;
+
+ /* Write the address/ID register */
+ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
+ falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+
+ EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2);
+ falcon_write(efx, &reg, MD_ID_REG_KER);
+
+ /* Write data */
+ EFX_POPULATE_OWORD_1(reg, MD_TXD, value);
+ falcon_write(efx, &reg, MD_TXD_REG_KER);
+
+ EFX_POPULATE_OWORD_2(reg,
+ MD_WRC, 1,
+ MD_GC, 0);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+
+ /* Wait for data to be written */
+ if (falcon_gmii_wait(efx) != 0) {
+ /* Abort the write operation */
+ EFX_POPULATE_OWORD_2(reg,
+ MD_WRC, 0,
+ MD_GC, 1);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+ udelay(10);
+ }
+
+ out:
+ spin_unlock_bh(&efx->phy_lock);
+}
+
+/* Reads a GMII register from a PHY connected to Falcon. If no value
+ * could be read, -1 will be returned. */
+static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
+{
+ struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
+ efx_oword_t reg;
+ int value = -1;
+
+ if (phy_addr == PHY_ADDR_INVALID)
+ return -1;
+
+ /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G)
+ * but the generic Linux code does not make any distinction or have
+ * any state for this.
+ * We spot the case where someone tried to talk 22 to a 45 PHY and
+ * redirect the request to the lowest numbered MMD as a clause45
+ * request. This is enough to allow simple queries like id and link
+ * state to succeed. TODO: We may need to do more in future.
+ */
+ if (!(phy_id & FALCON_PHY_ID_10G)) {
+ int mmd = ffs(efx->phy_op->mmds) - 1;
+ EFX_TRACE(efx, "Fixing erroneous clause22 read\n");
+ phy_addr = mdio_clause45_pack(phy_addr, mmd)
+ & FALCON_PHY_ID_ID_MASK;
+ }
+
+ spin_lock_bh(&efx->phy_lock);
+
+ /* Check MII not currently being accessed */
+ if (falcon_gmii_wait(efx) != 0)
+ goto out;
+
+ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
+ falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+
+ EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr);
+ falcon_write(efx, &reg, MD_ID_REG_KER);
+
+ /* Request data to be read */
+ EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+
+ /* Wait for data to become available */
+ value = falcon_gmii_wait(efx);
+ if (value == 0) {
+ falcon_read(efx, &reg, MD_RXD_REG_KER);
+ value = EFX_OWORD_FIELD(reg, MD_RXD);
+ EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n",
+ phy_id, addr, value);
+ } else {
+ /* Abort the read operation */
+ EFX_POPULATE_OWORD_2(reg,
+ MD_RIC, 0,
+ MD_GC, 1);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+
+ EFX_LOG(efx, "read from GMII 0x%x register %02x, got "
+ "error %d\n", phy_id, addr, value);
+ }
+
+ out:
+ spin_unlock_bh(&efx->phy_lock);
+
+ return value;
+}
+
+static void falcon_init_mdio(struct mii_if_info *gmii)
+{
+ gmii->mdio_read = falcon_mdio_read;
+ gmii->mdio_write = falcon_mdio_write;
+ gmii->phy_id_mask = FALCON_PHY_ID_MASK;
+ gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1);
+}
+
+static int falcon_probe_phy(struct efx_nic *efx)
+{
+ switch (efx->phy_type) {
+ case PHY_TYPE_10XPRESS:
+ efx->phy_op = &falcon_tenxpress_phy_ops;
+ break;
+ case PHY_TYPE_XFP:
+ efx->phy_op = &falcon_xfp_phy_ops;
+ break;
+ default:
+ EFX_ERR(efx, "Unknown PHY type %d\n",
+ efx->phy_type);
+ return -1;
+ }
+ return 0;
+}
+
+/* This call is responsible for hooking in the MAC and PHY operations */
+int falcon_probe_port(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Hook in PHY operations table */
+ rc = falcon_probe_phy(efx);
+ if (rc)
+ return rc;
+
+ /* Set up GMII structure for PHY */
+ efx->mii.supports_gmii = 1;
+ falcon_init_mdio(&efx->mii);
+
+ /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ efx->flow_control = EFX_FC_RX | EFX_FC_TX;
+ else
+ efx->flow_control = EFX_FC_RX;
+
+ /* Allocate buffer for stats */
+ rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
+ FALCON_MAC_STATS_SIZE);
+ if (rc)
+ return rc;
+ EFX_LOG(efx, "stats buffer at %llx (virt %p phys %lx)\n",
+ (unsigned long long)efx->stats_buffer.dma_addr,
+ efx->stats_buffer.addr,
+ virt_to_phys(efx->stats_buffer.addr));
+
+ return 0;
+}
+
+void falcon_remove_port(struct efx_nic *efx)
+{
+ falcon_free_buffer(efx, &efx->stats_buffer);
+}
+
+/**************************************************************************
+ *
+ * Multicast filtering
+ *
+ **************************************************************************
+ */
+
+void falcon_set_multicast_hash(struct efx_nic *efx)
+{
+ union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+
+ /* Broadcast packets go through the multicast hash filter.
+ * ether_crc_le() of the broadcast address is 0xbe2612ff
+ * so we always add bit 0xff to the mask.
+ */
+ set_bit_le(0xff, mc_hash->byte);
+
+ falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER);
+ falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER);
+}
+
+/**************************************************************************
+ *
+ * Device reset
+ *
+ **************************************************************************
+ */
+
+/* Resets NIC to known state. This routine must be called in process
+ * context and is allowed to sleep. */
+int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t glb_ctl_reg_ker;
+ int rc;
+
+ EFX_LOG(efx, "performing hardware reset (%d)\n", method);
+
+ /* Initiate device reset */
+ if (method == RESET_TYPE_WORLD) {
+ rc = pci_save_state(efx->pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to backup PCI state of primary "
+ "function prior to hardware reset\n");
+ goto fail1;
+ }
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ rc = pci_save_state(nic_data->pci_dev2);
+ if (rc) {
+ EFX_ERR(efx, "failed to backup PCI state of "
+ "secondary function prior to "
+ "hardware reset\n");
+ goto fail2;
+ }
+ }
+
+ EFX_POPULATE_OWORD_2(glb_ctl_reg_ker,
+ EXT_PHY_RST_DUR, 0x7,
+ SWRST, 1);
+ } else {
+ int reset_phy = (method == RESET_TYPE_INVISIBLE ?
+ EXCLUDE_FROM_RESET : 0);
+
+ EFX_POPULATE_OWORD_7(glb_ctl_reg_ker,
+ EXT_PHY_RST_CTL, reset_phy,
+ PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+ PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+ PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+ EE_RST_CTL, EXCLUDE_FROM_RESET,
+ EXT_PHY_RST_DUR, 0x7 /* 10ms */,
+ SWRST, 1);
+ }
+ falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+
+ EFX_LOG(efx, "waiting for hardware reset\n");
+ schedule_timeout_uninterruptible(HZ / 20);
+
+ /* Restore PCI configuration if needed */
+ if (method == RESET_TYPE_WORLD) {
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ rc = pci_restore_state(nic_data->pci_dev2);
+ if (rc) {
+ EFX_ERR(efx, "failed to restore PCI config for "
+ "the secondary function\n");
+ goto fail3;
+ }
+ }
+ rc = pci_restore_state(efx->pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to restore PCI config for the "
+ "primary function\n");
+ goto fail4;
+ }
+ EFX_LOG(efx, "successfully restored PCI config\n");
+ }
+
+ /* Assert that reset complete */
+ falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+ if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) {
+ rc = -ETIMEDOUT;
+ EFX_ERR(efx, "timed out waiting for hardware reset\n");
+ goto fail5;
+ }
+ EFX_LOG(efx, "hardware reset complete\n");
+
+ return 0;
+
+ /* pci_save_state() and pci_restore_state() MUST be called in pairs */
+fail2:
+fail3:
+ pci_restore_state(efx->pci_dev);
+fail1:
+fail4:
+fail5:
+ return rc;
+}
+
+/* Zeroes out the SRAM contents. This routine must be called in
+ * process context and is allowed to sleep.
+ */
+static int falcon_reset_sram(struct efx_nic *efx)
+{
+ efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker;
+ int count;
+
+ /* Set the SRAM wake/sleep GPIO appropriately. */
+ falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1);
+ falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+
+ /* Initiate SRAM reset */
+ EFX_POPULATE_OWORD_2(srm_cfg_reg_ker,
+ SRAM_OOB_BT_INIT_EN, 1,
+ SRM_NUM_BANKS_AND_BANK_SIZE, 0);
+ falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+
+ /* Wait for SRAM reset to complete */
+ count = 0;
+ do {
+ EFX_LOG(efx, "waiting for SRAM reset (attempt %d)...\n", count);
+
+ /* SRAM reset is slow; expect around 16ms */
+ schedule_timeout_uninterruptible(HZ / 50);
+
+ /* Check for reset complete */
+ falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+ if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) {
+ EFX_LOG(efx, "SRAM reset complete\n");
+
+ return 0;
+ }
+ } while (++count < 20); /* wait upto 0.4 sec */
+
+ EFX_ERR(efx, "timed out waiting for SRAM reset\n");
+ return -ETIMEDOUT;
+}
+
+/* Extract non-volatile configuration */
+static int falcon_probe_nvconfig(struct efx_nic *efx)
+{
+ struct falcon_nvconfig *nvconfig;
+ efx_oword_t nic_stat;
+ int device_id;
+ unsigned addr_len;
+ size_t offset, len;
+ int magic_num, struct_ver, board_rev;
+ int rc;
+
+ /* Find the boot device. */
+ falcon_read(efx, &nic_stat, NIC_STAT_REG);
+ if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) {
+ device_id = EE_SPI_FLASH;
+ addr_len = 3;
+ } else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) {
+ device_id = EE_SPI_EEPROM;
+ addr_len = 2;
+ } else {
+ return -ENODEV;
+ }
+
+ nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
+
+ /* Read the whole configuration structure into memory. */
+ for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
+ len = min(sizeof(*nvconfig) - offset,
+ (size_t) FALCON_SPI_MAX_LEN);
+ rc = falcon_spi_read(efx, device_id, SPI_READ,
+ NVCONFIG_BASE + offset, addr_len,
+ (char *)nvconfig + offset, len);
+ if (rc)
+ goto out;
+ }
+
+ /* Read the MAC addresses */
+ memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
+
+ /* Read the board configuration. */
+ magic_num = le16_to_cpu(nvconfig->board_magic_num);
+ struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
+
+ if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) {
+ EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x "
+ "therefore using defaults\n", magic_num, struct_ver);
+ efx->phy_type = PHY_TYPE_NONE;
+ efx->mii.phy_id = PHY_ADDR_INVALID;
+ board_rev = 0;
+ } else {
+ struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
+
+ efx->phy_type = v2->port0_phy_type;
+ efx->mii.phy_id = v2->port0_phy_addr;
+ board_rev = le16_to_cpu(v2->board_revision);
+ }
+
+ EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
+
+ efx_set_board_info(efx, board_rev);
+
+ out:
+ kfree(nvconfig);
+ return rc;
+}
+
+/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
+ * count, port speed). Set workaround and feature flags accordingly.
+ */
+static int falcon_probe_nic_variant(struct efx_nic *efx)
+{
+ efx_oword_t altera_build;
+
+ falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
+ if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
+ EFX_ERR(efx, "Falcon FPGA not supported\n");
+ return -ENODEV;
+ }
+
+ switch (FALCON_REV(efx)) {
+ case FALCON_REV_A0:
+ case 0xff:
+ EFX_ERR(efx, "Falcon rev A0 not supported\n");
+ return -ENODEV;
+
+ case FALCON_REV_A1:{
+ efx_oword_t nic_stat;
+
+ falcon_read(efx, &nic_stat, NIC_STAT_REG);
+
+ if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
+ EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+ return -ENODEV;
+ }
+ if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) {
+ EFX_ERR(efx, "1G mode not supported\n");
+ return -ENODEV;
+ }
+ break;
+ }
+
+ case FALCON_REV_B0:
+ break;
+
+ default:
+ EFX_ERR(efx, "Unknown Falcon rev %d\n", FALCON_REV(efx));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int falcon_probe_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data;
+ int rc;
+
+ /* Initialise I2C interface state */
+ efx->i2c.efx = efx;
+ efx->i2c.op = &falcon_i2c_bit_operations;
+ efx->i2c.sda = 1;
+ efx->i2c.scl = 1;
+
+ /* Allocate storage for hardware specific data */
+ nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
+ efx->nic_data = (void *) nic_data;
+
+ /* Determine number of ports etc. */
+ rc = falcon_probe_nic_variant(efx);
+ if (rc)
+ goto fail1;
+
+ /* Probe secondary function if expected */
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ struct pci_dev *dev = pci_dev_get(efx->pci_dev);
+
+ while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
+ dev))) {
+ if (dev->bus == efx->pci_dev->bus &&
+ dev->devfn == efx->pci_dev->devfn + 1) {
+ nic_data->pci_dev2 = dev;
+ break;
+ }
+ }
+ if (!nic_data->pci_dev2) {
+ EFX_ERR(efx, "failed to find secondary function\n");
+ rc = -ENODEV;
+ goto fail2;
+ }
+ }
+
+ /* Now we can reset the NIC */
+ rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
+ if (rc) {
+ EFX_ERR(efx, "failed to reset NIC\n");
+ goto fail3;
+ }
+
+ /* Allocate memory for INT_KER */
+ rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
+ if (rc)
+ goto fail4;
+ BUG_ON(efx->irq_status.dma_addr & 0x0f);
+
+ EFX_LOG(efx, "INT_KER at %llx (virt %p phys %lx)\n",
+ (unsigned long long)efx->irq_status.dma_addr,
+ efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
+
+ /* Read in the non-volatile configuration */
+ rc = falcon_probe_nvconfig(efx);
+ if (rc)
+ goto fail5;
+
+ return 0;
+
+ fail5:
+ falcon_free_buffer(efx, &efx->irq_status);
+ fail4:
+ /* fall-thru */
+ fail3:
+ if (nic_data->pci_dev2) {
+ pci_dev_put(nic_data->pci_dev2);
+ nic_data->pci_dev2 = NULL;
+ }
+ fail2:
+ /* fall-thru */
+ fail1:
+ kfree(efx->nic_data);
+ return rc;
+}
+
+/* This call performs hardware-specific global initialisation, such as
+ * defining the descriptor cache sizes and number of RSS channels.
+ * It does not set up any buffers, descriptor rings or event queues.
+ */
+int falcon_init_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *data;
+ efx_oword_t temp;
+ unsigned thresh;
+ int rc;
+
+ data = (struct falcon_nic_data *)efx->nic_data;
+
+ /* Set up the address region register. This is only needed
+ * for the B0 FPGA, but since we are just pushing in the
+ * reset defaults this may as well be unconditional. */
+ EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0,
+ ADR_REGION1, (1 << 16),
+ ADR_REGION2, (2 << 16),
+ ADR_REGION3, (3 << 16));
+ falcon_write(efx, &temp, ADR_REGION_REG_KER);
+
+ /* Use on-chip SRAM */
+ falcon_read(efx, &temp, NIC_STAT_REG);
+ EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
+ falcon_write(efx, &temp, NIC_STAT_REG);
+
+ /* Set buffer table mode */
+ EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
+ falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
+
+ rc = falcon_reset_sram(efx);
+ if (rc)
+ return rc;
+
+ /* Set positions of descriptor caches in SRAM. */
+ EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
+ falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
+ falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER);
+
+ /* Set TX descriptor cache size. */
+ BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER));
+ EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, TX_DC_ENTRIES_ORDER);
+ falcon_write(efx, &temp, TX_DC_CFG_REG_KER);
+
+ /* Set RX descriptor cache size. Set low watermark to size-8, as
+ * this allows most efficient prefetching.
+ */
+ BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER));
+ EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, RX_DC_ENTRIES_ORDER);
+ falcon_write(efx, &temp, RX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
+ falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER);
+
+ /* Clear the parity enables on the TX data fifos as
+ * they produce false parity errors because of timing issues
+ */
+ if (EFX_WORKAROUND_5129(efx)) {
+ falcon_read(efx, &temp, SPARE_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0);
+ falcon_write(efx, &temp, SPARE_REG_KER);
+ }
+
+ /* Enable all the genuinely fatal interrupts. (They are still
+ * masked by the overall interrupt mask, controlled by
+ * falcon_interrupts()).
+ *
+ * Note: All other fatal interrupts are enabled
+ */
+ EFX_POPULATE_OWORD_3(temp,
+ ILL_ADR_INT_KER_EN, 1,
+ RBUF_OWN_INT_KER_EN, 1,
+ TBUF_OWN_INT_KER_EN, 1);
+ EFX_INVERT_OWORD(temp);
+ falcon_write(efx, &temp, FATAL_INTR_REG_KER);
+
+ /* Set number of RSS queues for receive path. */
+ falcon_read(efx, &temp, RX_FILTER_CTL_REG);
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
+ else
+ EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
+ if (EFX_WORKAROUND_7244(efx)) {
+ EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
+ }
+ falcon_write(efx, &temp, RX_FILTER_CTL_REG);
+
+ falcon_setup_rss_indir_table(efx);
+
+ /* Setup RX. Wait for descriptor is broken and must
+ * be disabled. RXDP recovery shouldn't be needed, but is.
+ */
+ falcon_read(efx, &temp, RX_SELF_RST_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1);
+ EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1);
+ if (EFX_WORKAROUND_5583(efx))
+ EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1);
+ falcon_write(efx, &temp, RX_SELF_RST_REG_KER);
+
+ /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
+ * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
+ */
+ falcon_read(efx, &temp, TX_CFG2_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe);
+ EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1);
+ EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1);
+ EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1);
+ /* Enable SW_EV to inherit in char driver - assume harmless here */
+ EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1);
+ /* Prefetch threshold 2 => fetch when descriptor cache half empty */
+ EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
+ /* Squash TX of packets of 16 bytes or less */
+ if (FALCON_REV(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
+ EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
+ falcon_write(efx, &temp, TX_CFG2_REG_KER);
+
+ /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
+ * descriptors (which is bad).
+ */
+ falcon_read(efx, &temp, TX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0);
+ falcon_write(efx, &temp, TX_CFG_REG_KER);
+
+ /* RX config */
+ falcon_read(efx, &temp, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0);
+ if (EFX_WORKAROUND_7575(efx))
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
+ (3 * 4096) / 32);
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
+
+ /* RX FIFO flow control thresholds */
+ thresh = ((rx_xon_thresh_bytes >= 0) ?
+ rx_xon_thresh_bytes : efx->type->rx_xon_thresh);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256);
+ thresh = ((rx_xoff_thresh_bytes >= 0) ?
+ rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
+ /* RX control FIFO thresholds [32 entries] */
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
+ falcon_write(efx, &temp, RX_CFG_REG_KER);
+
+ /* Set destination of both TX and RX Flush events */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
+ falcon_write(efx, &temp, DP_CTRL_REG);
+ }
+
+ return 0;
+}
+
+void falcon_remove_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ falcon_free_buffer(efx, &efx->irq_status);
+
+ (void) falcon_reset_hw(efx, RESET_TYPE_ALL);
+
+ /* Release the second function after the reset */
+ if (nic_data->pci_dev2) {
+ pci_dev_put(nic_data->pci_dev2);
+ nic_data->pci_dev2 = NULL;
+ }
+
+ /* Tear down the private nic state */
+ kfree(efx->nic_data);
+ efx->nic_data = NULL;
+}
+
+void falcon_update_nic_stats(struct efx_nic *efx)
+{
+ efx_oword_t cnt;
+
+ falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER);
+ efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT);
+}
+
+/**************************************************************************
+ *
+ * Revision-dependent attributes used by efx.c
+ *
+ **************************************************************************
+ */
+
+struct efx_nic_type falcon_a_nic_type = {
+ .mem_bar = 2,
+ .mem_map_size = 0x20000,
+ .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1,
+ .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1,
+ .buf_tbl_base = BUF_TBL_KER_A1,
+ .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1,
+ .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1,
+ .txd_ring_mask = FALCON_TXD_RING_MASK,
+ .rxd_ring_mask = FALCON_RXD_RING_MASK,
+ .evq_size = FALCON_EVQ_SIZE,
+ .max_dma_mask = FALCON_DMA_MASK,
+ .tx_dma_mask = FALCON_TX_DMA_MASK,
+ .bug5391_mask = 0xf,
+ .rx_xoff_thresh = 2048,
+ .rx_xon_thresh = 512,
+ .rx_buffer_padding = 0x24,
+ .max_interrupt_mode = EFX_INT_MODE_MSI,
+ .phys_addr_channels = 4,
+};
+
+struct efx_nic_type falcon_b_nic_type = {
+ .mem_bar = 2,
+ /* Map everything up to and including the RSS indirection
+ * table. Don't map MSI-X table, MSI-X PBA since Linux
+ * requires that they not be mapped. */
+ .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800,
+ .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0,
+ .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0,
+ .buf_tbl_base = BUF_TBL_KER_B0,
+ .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0,
+ .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0,
+ .txd_ring_mask = FALCON_TXD_RING_MASK,
+ .rxd_ring_mask = FALCON_RXD_RING_MASK,
+ .evq_size = FALCON_EVQ_SIZE,
+ .max_dma_mask = FALCON_DMA_MASK,
+ .tx_dma_mask = FALCON_TX_DMA_MASK,
+ .bug5391_mask = 0,
+ .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */
+ .rx_xon_thresh = 27648, /* ~3*max MTU */
+ .rx_buffer_padding = 0,
+ .max_interrupt_mode = EFX_INT_MODE_MSIX,
+ .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
+ * interrupt handler only supports 32
+ * channels */
+};
+
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
new file mode 100644
index 00000000000..6117403b0c0
--- /dev/null
+++ b/drivers/net/sfc/falcon.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_H
+#define EFX_FALCON_H
+
+#include "net_driver.h"
+
+/*
+ * Falcon hardware control
+ */
+
+enum falcon_revision {
+ FALCON_REV_A0 = 0,
+ FALCON_REV_A1 = 1,
+ FALCON_REV_B0 = 2,
+};
+
+#define FALCON_REV(efx) ((efx)->pci_dev->revision)
+
+extern struct efx_nic_type falcon_a_nic_type;
+extern struct efx_nic_type falcon_b_nic_type;
+
+/**************************************************************************
+ *
+ * Externs
+ *
+ **************************************************************************
+ */
+
+/* TX data path */
+extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
+extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
+
+/* RX data path */
+extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
+extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
+
+/* Event data path */
+extern int falcon_probe_eventq(struct efx_channel *channel);
+extern int falcon_init_eventq(struct efx_channel *channel);
+extern void falcon_fini_eventq(struct efx_channel *channel);
+extern void falcon_remove_eventq(struct efx_channel *channel);
+extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota);
+extern void falcon_eventq_read_ack(struct efx_channel *channel);
+
+/* Ports */
+extern int falcon_probe_port(struct efx_nic *efx);
+extern void falcon_remove_port(struct efx_nic *efx);
+
+/* MAC/PHY */
+extern int falcon_xaui_link_ok(struct efx_nic *efx);
+extern int falcon_dma_stats(struct efx_nic *efx,
+ unsigned int done_offset);
+extern void falcon_drain_tx_fifo(struct efx_nic *efx);
+extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
+
+/* Interrupts and test events */
+extern int falcon_init_interrupt(struct efx_nic *efx);
+extern void falcon_enable_interrupts(struct efx_nic *efx);
+extern void falcon_generate_test_event(struct efx_channel *channel,
+ unsigned int magic);
+extern void falcon_generate_interrupt(struct efx_nic *efx);
+extern void falcon_set_int_moderation(struct efx_channel *channel);
+extern void falcon_disable_interrupts(struct efx_nic *efx);
+extern void falcon_fini_interrupt(struct efx_nic *efx);
+
+/* Global Resources */
+extern int falcon_probe_nic(struct efx_nic *efx);
+extern int falcon_probe_resources(struct efx_nic *efx);
+extern int falcon_init_nic(struct efx_nic *efx);
+extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
+extern void falcon_remove_resources(struct efx_nic *efx);
+extern void falcon_remove_nic(struct efx_nic *efx);
+extern void falcon_update_nic_stats(struct efx_nic *efx);
+extern void falcon_set_multicast_hash(struct efx_nic *efx);
+extern int falcon_reset_xaui(struct efx_nic *efx);
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ */
+
+#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
+#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
+
+/* Retrieve statistic from statistics block */
+#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \
+ if (FALCON_STAT_WIDTH(falcon_stat) == 16) \
+ (efx)->mac_stats.efx_stat += le16_to_cpu( \
+ *((__force __le16 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \
+ (efx)->mac_stats.efx_stat += le32_to_cpu( \
+ *((__force __le32 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ else \
+ (efx)->mac_stats.efx_stat += le64_to_cpu( \
+ *((__force __le64 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ } while (0)
+
+#define FALCON_MAC_STATS_SIZE 0x100
+
+#define MAC_DATA_LBN 0
+#define MAC_DATA_WIDTH 32
+
+extern void falcon_generate_event(struct efx_channel *channel,
+ efx_qword_t *event);
+
+#endif /* EFX_FALCON_H */
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
new file mode 100644
index 00000000000..0485a63eaff
--- /dev/null
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -0,0 +1,1135 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_HWDEFS_H
+#define EFX_FALCON_HWDEFS_H
+
+/*
+ * Falcon hardware value definitions.
+ * Falcon is the internal codename for the SFC4000 controller that is
+ * present in SFE400X evaluation boards
+ */
+
+/**************************************************************************
+ *
+ * Falcon registers
+ *
+ **************************************************************************
+ */
+
+/* Address region register */
+#define ADR_REGION_REG_KER 0x00
+#define ADR_REGION0_LBN 0
+#define ADR_REGION0_WIDTH 18
+#define ADR_REGION1_LBN 32
+#define ADR_REGION1_WIDTH 18
+#define ADR_REGION2_LBN 64
+#define ADR_REGION2_WIDTH 18
+#define ADR_REGION3_LBN 96
+#define ADR_REGION3_WIDTH 18
+
+/* Interrupt enable register */
+#define INT_EN_REG_KER 0x0010
+#define KER_INT_KER_LBN 3
+#define KER_INT_KER_WIDTH 1
+#define DRV_INT_EN_KER_LBN 0
+#define DRV_INT_EN_KER_WIDTH 1
+
+/* Interrupt status address register */
+#define INT_ADR_REG_KER 0x0030
+#define NORM_INT_VEC_DIS_KER_LBN 64
+#define NORM_INT_VEC_DIS_KER_WIDTH 1
+#define INT_ADR_KER_LBN 0
+#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */
+
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define INT_ACK_REG_KER_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* SPI host command register */
+#define EE_SPI_HCMD_REG_KER 0x0100
+#define EE_SPI_HCMD_CMD_EN_LBN 31
+#define EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define EE_WR_TIMER_ACTIVE_LBN 28
+#define EE_WR_TIMER_ACTIVE_WIDTH 1
+#define EE_SPI_HCMD_SF_SEL_LBN 24
+#define EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define EE_SPI_EEPROM 0
+#define EE_SPI_FLASH 1
+#define EE_SPI_HCMD_DABCNT_LBN 16
+#define EE_SPI_HCMD_DABCNT_WIDTH 5
+#define EE_SPI_HCMD_READ_LBN 15
+#define EE_SPI_HCMD_READ_WIDTH 1
+#define EE_SPI_READ 1
+#define EE_SPI_WRITE 0
+#define EE_SPI_HCMD_DUBCNT_LBN 12
+#define EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define EE_SPI_HCMD_ADBCNT_LBN 8
+#define EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define EE_SPI_HCMD_ENC_LBN 0
+#define EE_SPI_HCMD_ENC_WIDTH 8
+
+/* SPI host address register */
+#define EE_SPI_HADR_REG_KER 0x0110
+#define EE_SPI_HADR_ADR_LBN 0
+#define EE_SPI_HADR_ADR_WIDTH 24
+
+/* SPI host data register */
+#define EE_SPI_HDATA_REG_KER 0x0120
+
+/* PCIE CORE ACCESS REG */
+#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
+#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
+#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700
+#define PCIE_CORE_ADDR_ACK_FREQ 0x70C
+
+/* NIC status register */
+#define NIC_STAT_REG 0x0200
+#define ONCHIP_SRAM_LBN 16
+#define ONCHIP_SRAM_WIDTH 1
+#define SF_PRST_LBN 9
+#define SF_PRST_WIDTH 1
+#define EE_PRST_LBN 8
+#define EE_PRST_WIDTH 1
+/* See pic_mode_t for decoding of this field */
+/* These bit definitions are extrapolated from the list of numerical
+ * values for STRAP_PINS.
+ */
+#define STRAP_10G_LBN 2
+#define STRAP_10G_WIDTH 1
+#define STRAP_PCIE_LBN 0
+#define STRAP_PCIE_WIDTH 1
+
+/* GPIO control register */
+#define GPIO_CTL_REG_KER 0x0210
+#define GPIO_OUTPUTS_LBN (16)
+#define GPIO_OUTPUTS_WIDTH (4)
+#define GPIO_INPUTS_LBN (8)
+#define GPIO_DIRECTION_LBN (24)
+#define GPIO_DIRECTION_WIDTH (4)
+#define GPIO_DIRECTION_OUT (1)
+#define GPIO_SRAM_SLEEP (1 << 1)
+
+#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3)
+#define GPIO3_OEN_WIDTH 1
+#define GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2)
+#define GPIO2_OEN_WIDTH 1
+#define GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1)
+#define GPIO1_OEN_WIDTH 1
+#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0)
+#define GPIO0_OEN_WIDTH 1
+
+#define GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3)
+#define GPIO3_OUT_WIDTH 1
+#define GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2)
+#define GPIO2_OUT_WIDTH 1
+#define GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1)
+#define GPIO1_OUT_WIDTH 1
+#define GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0)
+#define GPIO0_OUT_WIDTH 1
+
+#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3)
+#define GPIO3_IN_WIDTH 1
+#define GPIO2_IN_WIDTH 1
+#define GPIO1_IN_WIDTH 1
+#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0)
+#define GPIO0_IN_WIDTH 1
+
+/* Global control register */
+#define GLB_CTL_REG_KER 0x0220
+#define EXT_PHY_RST_CTL_LBN 63
+#define EXT_PHY_RST_CTL_WIDTH 1
+#define PCIE_SD_RST_CTL_LBN 61
+#define PCIE_SD_RST_CTL_WIDTH 1
+
+#define PCIE_NSTCK_RST_CTL_LBN 58
+#define PCIE_NSTCK_RST_CTL_WIDTH 1
+#define PCIE_CORE_RST_CTL_LBN 57
+#define PCIE_CORE_RST_CTL_WIDTH 1
+#define EE_RST_CTL_LBN 49
+#define EE_RST_CTL_WIDTH 1
+#define RST_XGRX_LBN 24
+#define RST_XGRX_WIDTH 1
+#define RST_XGTX_LBN 23
+#define RST_XGTX_WIDTH 1
+#define RST_EM_LBN 22
+#define RST_EM_WIDTH 1
+#define EXT_PHY_RST_DUR_LBN 1
+#define EXT_PHY_RST_DUR_WIDTH 3
+#define SWRST_LBN 0
+#define SWRST_WIDTH 1
+#define INCLUDE_IN_RESET 0
+#define EXCLUDE_FROM_RESET 1
+
+/* Fatal interrupt register */
+#define FATAL_INTR_REG_KER 0x0230
+#define RBUF_OWN_INT_KER_EN_LBN 39
+#define RBUF_OWN_INT_KER_EN_WIDTH 1
+#define TBUF_OWN_INT_KER_EN_LBN 38
+#define TBUF_OWN_INT_KER_EN_WIDTH 1
+#define ILL_ADR_INT_KER_EN_LBN 33
+#define ILL_ADR_INT_KER_EN_WIDTH 1
+#define MEM_PERR_INT_KER_LBN 8
+#define MEM_PERR_INT_KER_WIDTH 1
+#define INT_KER_ERROR_LBN 0
+#define INT_KER_ERROR_WIDTH 12
+
+#define DP_CTRL_REG 0x250
+#define FLS_EVQ_ID_LBN 0
+#define FLS_EVQ_ID_WIDTH 11
+
+#define MEM_STAT_REG_KER 0x260
+
+/* Debug probe register */
+#define DEBUG_BLK_SEL_MISC 7
+#define DEBUG_BLK_SEL_SERDES 6
+#define DEBUG_BLK_SEL_EM 5
+#define DEBUG_BLK_SEL_SR 4
+#define DEBUG_BLK_SEL_EV 3
+#define DEBUG_BLK_SEL_RX 2
+#define DEBUG_BLK_SEL_TX 1
+#define DEBUG_BLK_SEL_BIU 0
+
+/* FPGA build version */
+#define ALTERA_BUILD_REG_KER 0x0300
+#define VER_ALL_LBN 0
+#define VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define SPARE_REG_KER 0x310
+#define MEM_PERR_EN_TX_DATA_LBN 72
+#define MEM_PERR_EN_TX_DATA_WIDTH 2
+
+/* Timer table for kernel access */
+#define TIMER_CMD_REG_KER 0x420
+#define TIMER_MODE_LBN 12
+#define TIMER_MODE_WIDTH 2
+#define TIMER_MODE_DIS 0
+#define TIMER_MODE_INT_HLDOFF 2
+#define TIMER_VAL_LBN 0
+#define TIMER_VAL_WIDTH 12
+
+/* Driver generated event register */
+#define DRV_EV_REG_KER 0x440
+#define DRV_EV_QID_LBN 64
+#define DRV_EV_QID_WIDTH 12
+#define DRV_EV_DATA_LBN 0
+#define DRV_EV_DATA_WIDTH 64
+
+/* Buffer table configuration register */
+#define BUF_TBL_CFG_REG_KER 0x600
+#define BUF_TBL_MODE_LBN 3
+#define BUF_TBL_MODE_WIDTH 1
+#define BUF_TBL_MODE_HALF 0
+#define BUF_TBL_MODE_FULL 1
+
+/* SRAM receive descriptor cache configuration register */
+#define SRM_RX_DC_CFG_REG_KER 0x610
+#define SRM_RX_DC_BASE_ADR_LBN 0
+#define SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM transmit descriptor cache configuration register */
+#define SRM_TX_DC_CFG_REG_KER 0x620
+#define SRM_TX_DC_BASE_ADR_LBN 0
+#define SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM configuration register */
+#define SRM_CFG_REG_KER 0x630
+#define SRAM_OOB_BT_INIT_EN_LBN 3
+#define SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+#define SRM_NB_BSZ_1BANKS_2M 0
+#define SRM_NB_BSZ_1BANKS_4M 1
+#define SRM_NB_BSZ_1BANKS_8M 2
+#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */
+#define SRM_NB_BSZ_2BANKS_4M 4
+#define SRM_NB_BSZ_2BANKS_8M 5
+#define SRM_NB_BSZ_2BANKS_16M 6
+#define SRM_NB_BSZ_RESERVED 7
+
+/* Special buffer table update register */
+#define BUF_TBL_UPD_REG_KER 0x0650
+#define BUF_UPD_CMD_LBN 63
+#define BUF_UPD_CMD_WIDTH 1
+#define BUF_CLR_CMD_LBN 62
+#define BUF_CLR_CMD_WIDTH 1
+#define BUF_CLR_END_ID_LBN 32
+#define BUF_CLR_END_ID_WIDTH 20
+#define BUF_CLR_START_ID_LBN 0
+#define BUF_CLR_START_ID_WIDTH 20
+
+/* Receive configuration register */
+#define RX_CFG_REG_KER 0x800
+
+/* B0 */
+#define RX_INGR_EN_B0_LBN 47
+#define RX_INGR_EN_B0_WIDTH 1
+#define RX_DESC_PUSH_EN_B0_LBN 43
+#define RX_DESC_PUSH_EN_B0_WIDTH 1
+#define RX_XON_TX_TH_B0_LBN 33
+#define RX_XON_TX_TH_B0_WIDTH 5
+#define RX_XOFF_TX_TH_B0_LBN 28
+#define RX_XOFF_TX_TH_B0_WIDTH 5
+#define RX_USR_BUF_SIZE_B0_LBN 19
+#define RX_USR_BUF_SIZE_B0_WIDTH 9
+#define RX_XON_MAC_TH_B0_LBN 10
+#define RX_XON_MAC_TH_B0_WIDTH 9
+#define RX_XOFF_MAC_TH_B0_LBN 1
+#define RX_XOFF_MAC_TH_B0_WIDTH 9
+#define RX_XOFF_MAC_EN_B0_LBN 0
+#define RX_XOFF_MAC_EN_B0_WIDTH 1
+
+/* A1 */
+#define RX_DESC_PUSH_EN_A1_LBN 35
+#define RX_DESC_PUSH_EN_A1_WIDTH 1
+#define RX_XON_TX_TH_A1_LBN 25
+#define RX_XON_TX_TH_A1_WIDTH 5
+#define RX_XOFF_TX_TH_A1_LBN 20
+#define RX_XOFF_TX_TH_A1_WIDTH 5
+#define RX_USR_BUF_SIZE_A1_LBN 11
+#define RX_USR_BUF_SIZE_A1_WIDTH 9
+#define RX_XON_MAC_TH_A1_LBN 6
+#define RX_XON_MAC_TH_A1_WIDTH 5
+#define RX_XOFF_MAC_TH_A1_LBN 1
+#define RX_XOFF_MAC_TH_A1_WIDTH 5
+#define RX_XOFF_MAC_EN_A1_LBN 0
+#define RX_XOFF_MAC_EN_A1_WIDTH 1
+
+/* Receive filter control register */
+#define RX_FILTER_CTL_REG 0x810
+#define UDP_FULL_SRCH_LIMIT_LBN 32
+#define UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define NUM_KER_LBN 24
+#define NUM_KER_WIDTH 2
+#define UDP_WILD_SRCH_LIMIT_LBN 16
+#define UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define TCP_WILD_SRCH_LIMIT_LBN 8
+#define TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define TCP_FULL_SRCH_LIMIT_LBN 0
+#define TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define RX_FLUSH_DESCQ_REG_KER 0x0820
+#define RX_FLUSH_DESCQ_CMD_LBN 24
+#define RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define RX_FLUSH_DESCQ_LBN 0
+#define RX_FLUSH_DESCQ_WIDTH 12
+
+/* Receive descriptor update register */
+#define RX_DESC_UPD_REG_KER_DWORD (0x830 + 12)
+#define RX_DESC_WPTR_DWORD_LBN 0
+#define RX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Receive descriptor cache configuration register */
+#define RX_DC_CFG_REG_KER 0x840
+#define RX_DC_SIZE_LBN 0
+#define RX_DC_SIZE_WIDTH 2
+
+#define RX_DC_PF_WM_REG_KER 0x850
+#define RX_DC_PF_LWM_LBN 0
+#define RX_DC_PF_LWM_WIDTH 6
+
+/* RX no descriptor drop counter */
+#define RX_NODESC_DROP_REG_KER 0x880
+#define RX_NODESC_DROP_CNT_LBN 0
+#define RX_NODESC_DROP_CNT_WIDTH 16
+
+/* RX black magic register */
+#define RX_SELF_RST_REG_KER 0x890
+#define RX_ISCSI_DIS_LBN 17
+#define RX_ISCSI_DIS_WIDTH 1
+#define RX_NODESC_WAIT_DIS_LBN 9
+#define RX_NODESC_WAIT_DIS_WIDTH 1
+#define RX_RECOVERY_EN_LBN 8
+#define RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define TX_FLUSH_DESCQ_CMD_LBN 12
+#define TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define TX_FLUSH_DESCQ_LBN 0
+#define TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit descriptor update register */
+#define TX_DESC_UPD_REG_KER_DWORD (0xa10 + 12)
+#define TX_DESC_WPTR_DWORD_LBN 0
+#define TX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Transmit descriptor cache configuration register */
+#define TX_DC_CFG_REG_KER 0xa20
+#define TX_DC_SIZE_LBN 0
+#define TX_DC_SIZE_WIDTH 2
+
+/* Transmit checksum configuration register (A0/A1 only) */
+#define TX_CHKSM_CFG_REG_KER_A1 0xa30
+
+/* Transmit configuration register */
+#define TX_CFG_REG_KER 0xa50
+#define TX_NO_EOP_DISC_EN_LBN 5
+#define TX_NO_EOP_DISC_EN_WIDTH 1
+
+/* Transmit configuration register 2 */
+#define TX_CFG2_REG_KER 0xa80
+#define TX_CSR_PUSH_EN_LBN 89
+#define TX_CSR_PUSH_EN_WIDTH 1
+#define TX_RX_SPACER_LBN 64
+#define TX_RX_SPACER_WIDTH 8
+#define TX_SW_EV_EN_LBN 59
+#define TX_SW_EV_EN_WIDTH 1
+#define TX_RX_SPACER_EN_LBN 57
+#define TX_RX_SPACER_EN_WIDTH 1
+#define TX_PREF_THRESHOLD_LBN 19
+#define TX_PREF_THRESHOLD_WIDTH 2
+#define TX_ONE_PKT_PER_Q_LBN 18
+#define TX_ONE_PKT_PER_Q_WIDTH 1
+#define TX_DIS_NON_IP_EV_LBN 17
+#define TX_DIS_NON_IP_EV_WIDTH 1
+#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
+#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
+
+/* PHY management transmit data register */
+#define MD_TXD_REG_KER 0xc00
+#define MD_TXD_LBN 0
+#define MD_TXD_WIDTH 16
+
+/* PHY management receive data register */
+#define MD_RXD_REG_KER 0xc10
+#define MD_RXD_LBN 0
+#define MD_RXD_WIDTH 16
+
+/* PHY management configuration & status register */
+#define MD_CS_REG_KER 0xc20
+#define MD_GC_LBN 4
+#define MD_GC_WIDTH 1
+#define MD_RIC_LBN 2
+#define MD_RIC_WIDTH 1
+#define MD_RDC_LBN 1
+#define MD_RDC_WIDTH 1
+#define MD_WRC_LBN 0
+#define MD_WRC_WIDTH 1
+
+/* PHY management PHY address register */
+#define MD_PHY_ADR_REG_KER 0xc30
+#define MD_PHY_ADR_LBN 0
+#define MD_PHY_ADR_WIDTH 16
+
+/* PHY management ID register */
+#define MD_ID_REG_KER 0xc40
+#define MD_PRT_ADR_LBN 11
+#define MD_PRT_ADR_WIDTH 5
+#define MD_DEV_ADR_LBN 6
+#define MD_DEV_ADR_WIDTH 5
+/* Used for writing both at once */
+#define MD_PRT_DEV_ADR_LBN 6
+#define MD_PRT_DEV_ADR_WIDTH 10
+
+/* PHY management status & mask register (DWORD read only) */
+#define MD_STAT_REG_KER 0xc50
+#define MD_BSERR_LBN 2
+#define MD_BSERR_WIDTH 1
+#define MD_LNFL_LBN 1
+#define MD_LNFL_WIDTH 1
+#define MD_BSY_LBN 0
+#define MD_BSY_WIDTH 1
+
+/* Port 0 and 1 MAC stats registers */
+#define MAC0_STAT_DMA_REG_KER 0xc60
+#define MAC_STAT_DMA_CMD_LBN 48
+#define MAC_STAT_DMA_CMD_WIDTH 1
+#define MAC_STAT_DMA_ADR_LBN 0
+#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/* Port 0 and 1 MAC control registers */
+#define MAC0_CTRL_REG_KER 0xc80
+#define MAC_XOFF_VAL_LBN 16
+#define MAC_XOFF_VAL_WIDTH 16
+#define TXFIFO_DRAIN_EN_B0_LBN 7
+#define TXFIFO_DRAIN_EN_B0_WIDTH 1
+#define MAC_BCAD_ACPT_LBN 4
+#define MAC_BCAD_ACPT_WIDTH 1
+#define MAC_UC_PROM_LBN 3
+#define MAC_UC_PROM_WIDTH 1
+#define MAC_LINK_STATUS_LBN 2
+#define MAC_LINK_STATUS_WIDTH 1
+#define MAC_SPEED_LBN 0
+#define MAC_SPEED_WIDTH 2
+
+/* 10G XAUI XGXS default values */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
+
+/* Multicast address hash table */
+#define MAC_MCAST_HASH_REG0_KER 0xca0
+#define MAC_MCAST_HASH_REG1_KER 0xcb0
+
+/* GMAC registers */
+#define FALCON_GMAC_REGBANK 0xe00
+#define FALCON_GMAC_REGBANK_SIZE 0x200
+#define FALCON_GMAC_REG_SIZE 0x10
+
+/* XMAC registers */
+#define FALCON_XMAC_REGBANK 0x1200
+#define FALCON_XMAC_REGBANK_SIZE 0x200
+#define FALCON_XMAC_REG_SIZE 0x10
+
+/* XGMAC address register low */
+#define XM_ADR_LO_REG_MAC 0x00
+#define XM_ADR_3_LBN 24
+#define XM_ADR_3_WIDTH 8
+#define XM_ADR_2_LBN 16
+#define XM_ADR_2_WIDTH 8
+#define XM_ADR_1_LBN 8
+#define XM_ADR_1_WIDTH 8
+#define XM_ADR_0_LBN 0
+#define XM_ADR_0_WIDTH 8
+
+/* XGMAC address register high */
+#define XM_ADR_HI_REG_MAC 0x01
+#define XM_ADR_5_LBN 8
+#define XM_ADR_5_WIDTH 8
+#define XM_ADR_4_LBN 0
+#define XM_ADR_4_WIDTH 8
+
+/* XGMAC global configuration */
+#define XM_GLB_CFG_REG_MAC 0x02
+#define XM_RX_STAT_EN_LBN 11
+#define XM_RX_STAT_EN_WIDTH 1
+#define XM_TX_STAT_EN_LBN 10
+#define XM_TX_STAT_EN_WIDTH 1
+#define XM_RX_JUMBO_MODE_LBN 6
+#define XM_RX_JUMBO_MODE_WIDTH 1
+#define XM_INTCLR_MODE_LBN 3
+#define XM_INTCLR_MODE_WIDTH 1
+#define XM_CORE_RST_LBN 0
+#define XM_CORE_RST_WIDTH 1
+
+/* XGMAC transmit configuration */
+#define XM_TX_CFG_REG_MAC 0x03
+#define XM_IPG_LBN 16
+#define XM_IPG_WIDTH 4
+#define XM_FCNTL_LBN 10
+#define XM_FCNTL_WIDTH 1
+#define XM_TXCRC_LBN 8
+#define XM_TXCRC_WIDTH 1
+#define XM_AUTO_PAD_LBN 5
+#define XM_AUTO_PAD_WIDTH 1
+#define XM_TX_PRMBL_LBN 2
+#define XM_TX_PRMBL_WIDTH 1
+#define XM_TXEN_LBN 1
+#define XM_TXEN_WIDTH 1
+
+/* XGMAC receive configuration */
+#define XM_RX_CFG_REG_MAC 0x04
+#define XM_PASS_CRC_ERR_LBN 25
+#define XM_PASS_CRC_ERR_WIDTH 1
+#define XM_ACPT_ALL_MCAST_LBN 11
+#define XM_ACPT_ALL_MCAST_WIDTH 1
+#define XM_ACPT_ALL_UCAST_LBN 9
+#define XM_ACPT_ALL_UCAST_WIDTH 1
+#define XM_AUTO_DEPAD_LBN 8
+#define XM_AUTO_DEPAD_WIDTH 1
+#define XM_RXEN_LBN 1
+#define XM_RXEN_WIDTH 1
+
+/* XGMAC management interrupt mask register */
+#define XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define XM_MSK_PRMBLE_ERR_LBN 2
+#define XM_MSK_PRMBLE_ERR_WIDTH 1
+#define XM_MSK_RMTFLT_LBN 1
+#define XM_MSK_RMTFLT_WIDTH 1
+#define XM_MSK_LCLFLT_LBN 0
+#define XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define XM_FC_REG_MAC 0x7
+#define XM_PAUSE_TIME_LBN 16
+#define XM_PAUSE_TIME_WIDTH 16
+#define XM_DIS_FCNTL_LBN 0
+#define XM_DIS_FCNTL_WIDTH 1
+
+/* XGMAC pause time count register */
+#define XM_PAUSE_TIME_REG_MAC 0x9
+
+/* XGMAC transmit parameter register */
+#define XM_TX_PARAM_REG_MAC 0x0d
+#define XM_TX_JUMBO_MODE_LBN 31
+#define XM_TX_JUMBO_MODE_WIDTH 1
+#define XM_MAX_TX_FRM_SIZE_LBN 16
+#define XM_MAX_TX_FRM_SIZE_WIDTH 14
+
+/* XGMAC receive parameter register */
+#define XM_RX_PARAM_REG_MAC 0x0e
+#define XM_MAX_RX_FRM_SIZE_LBN 0
+#define XM_MAX_RX_FRM_SIZE_WIDTH 14
+
+/* XGMAC management interrupt status register */
+#define XM_MGT_INT_REG_MAC_B0 0x0f
+#define XM_PRMBLE_ERR 2
+#define XM_PRMBLE_WIDTH 1
+#define XM_RMTFLT_LBN 1
+#define XM_RMTFLT_WIDTH 1
+#define XM_LCLFLT_LBN 0
+#define XM_LCLFLT_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset register */
+#define XX_PWR_RST_REG_MAC 0x10
+
+#define XX_PWRDND_EN_LBN 15
+#define XX_PWRDND_EN_WIDTH 1
+#define XX_PWRDNC_EN_LBN 14
+#define XX_PWRDNC_EN_WIDTH 1
+#define XX_PWRDNB_EN_LBN 13
+#define XX_PWRDNB_EN_WIDTH 1
+#define XX_PWRDNA_EN_LBN 12
+#define XX_PWRDNA_EN_WIDTH 1
+#define XX_RSTPLLCD_EN_LBN 9
+#define XX_RSTPLLCD_EN_WIDTH 1
+#define XX_RSTPLLAB_EN_LBN 8
+#define XX_RSTPLLAB_EN_WIDTH 1
+#define XX_RESETD_EN_LBN 7
+#define XX_RESETD_EN_WIDTH 1
+#define XX_RESETC_EN_LBN 6
+#define XX_RESETC_EN_WIDTH 1
+#define XX_RESETB_EN_LBN 5
+#define XX_RESETB_EN_WIDTH 1
+#define XX_RESETA_EN_LBN 4
+#define XX_RESETA_EN_WIDTH 1
+#define XX_RSTXGXSRX_EN_LBN 2
+#define XX_RSTXGXSRX_EN_WIDTH 1
+#define XX_RSTXGXSTX_EN_LBN 1
+#define XX_RSTXGXSTX_EN_WIDTH 1
+#define XX_RST_XX_EN_LBN 0
+#define XX_RST_XX_EN_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset control register */
+#define XX_SD_CTL_REG_MAC 0x11
+#define XX_HIDRVD_LBN 15
+#define XX_HIDRVD_WIDTH 1
+#define XX_LODRVD_LBN 14
+#define XX_LODRVD_WIDTH 1
+#define XX_HIDRVC_LBN 13
+#define XX_HIDRVC_WIDTH 1
+#define XX_LODRVC_LBN 12
+#define XX_LODRVC_WIDTH 1
+#define XX_HIDRVB_LBN 11
+#define XX_HIDRVB_WIDTH 1
+#define XX_LODRVB_LBN 10
+#define XX_LODRVB_WIDTH 1
+#define XX_HIDRVA_LBN 9
+#define XX_HIDRVA_WIDTH 1
+#define XX_LODRVA_LBN 8
+#define XX_LODRVA_WIDTH 1
+
+#define XX_TXDRV_CTL_REG_MAC 0x12
+#define XX_DEQD_LBN 28
+#define XX_DEQD_WIDTH 4
+#define XX_DEQC_LBN 24
+#define XX_DEQC_WIDTH 4
+#define XX_DEQB_LBN 20
+#define XX_DEQB_WIDTH 4
+#define XX_DEQA_LBN 16
+#define XX_DEQA_WIDTH 4
+#define XX_DTXD_LBN 12
+#define XX_DTXD_WIDTH 4
+#define XX_DTXC_LBN 8
+#define XX_DTXC_WIDTH 4
+#define XX_DTXB_LBN 4
+#define XX_DTXB_WIDTH 4
+#define XX_DTXA_LBN 0
+#define XX_DTXA_WIDTH 4
+
+/* XAUI XGXS core status register */
+#define XX_FORCE_SIG_DECODE_FORCED 0xff
+#define XX_CORE_STAT_REG_MAC 0x16
+#define XX_ALIGN_DONE_LBN 20
+#define XX_ALIGN_DONE_WIDTH 1
+#define XX_SYNC_STAT_LBN 16
+#define XX_SYNC_STAT_WIDTH 4
+#define XX_SYNC_STAT_DECODE_SYNCED 0xf
+#define XX_COMMA_DET_LBN 12
+#define XX_COMMA_DET_WIDTH 4
+#define XX_COMMA_DET_DECODE_DETECTED 0xf
+#define XX_COMMA_DET_RESET 0xf
+#define XX_CHARERR_LBN 4
+#define XX_CHARERR_WIDTH 4
+#define XX_CHARERR_RESET 0xf
+#define XX_DISPERR_LBN 0
+#define XX_DISPERR_WIDTH 4
+#define XX_DISPERR_RESET 0xf
+
+/* Receive filter table */
+#define RX_FILTER_TBL0 0xF00000
+
+/* Receive descriptor pointer table */
+#define RX_DESC_PTR_TBL_KER_A1 0x11800
+#define RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define RX_DESC_PTR_TBL_KER_P0 0x900
+#define RX_ISCSI_DDIG_EN_LBN 88
+#define RX_ISCSI_DDIG_EN_WIDTH 1
+#define RX_ISCSI_HDIG_EN_LBN 87
+#define RX_ISCSI_HDIG_EN_WIDTH 1
+#define RX_DESCQ_BUF_BASE_ID_LBN 36
+#define RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define RX_DESCQ_EVQ_ID_LBN 24
+#define RX_DESCQ_EVQ_ID_WIDTH 12
+#define RX_DESCQ_OWNER_ID_LBN 10
+#define RX_DESCQ_OWNER_ID_WIDTH 14
+#define RX_DESCQ_LABEL_LBN 5
+#define RX_DESCQ_LABEL_WIDTH 5
+#define RX_DESCQ_SIZE_LBN 3
+#define RX_DESCQ_SIZE_WIDTH 2
+#define RX_DESCQ_SIZE_4K 3
+#define RX_DESCQ_SIZE_2K 2
+#define RX_DESCQ_SIZE_1K 1
+#define RX_DESCQ_SIZE_512 0
+#define RX_DESCQ_TYPE_LBN 2
+#define RX_DESCQ_TYPE_WIDTH 1
+#define RX_DESCQ_JUMBO_LBN 1
+#define RX_DESCQ_JUMBO_WIDTH 1
+#define RX_DESCQ_EN_LBN 0
+#define RX_DESCQ_EN_WIDTH 1
+
+/* Transmit descriptor pointer table */
+#define TX_DESC_PTR_TBL_KER_A1 0x11900
+#define TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define TX_DESC_PTR_TBL_KER_P0 0xa40
+#define TX_NON_IP_DROP_DIS_B0_LBN 91
+#define TX_NON_IP_DROP_DIS_B0_WIDTH 1
+#define TX_IP_CHKSM_DIS_B0_LBN 90
+#define TX_IP_CHKSM_DIS_B0_WIDTH 1
+#define TX_TCP_CHKSM_DIS_B0_LBN 89
+#define TX_TCP_CHKSM_DIS_B0_WIDTH 1
+#define TX_DESCQ_EN_LBN 88
+#define TX_DESCQ_EN_WIDTH 1
+#define TX_ISCSI_DDIG_EN_LBN 87
+#define TX_ISCSI_DDIG_EN_WIDTH 1
+#define TX_ISCSI_HDIG_EN_LBN 86
+#define TX_ISCSI_HDIG_EN_WIDTH 1
+#define TX_DESCQ_BUF_BASE_ID_LBN 36
+#define TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define TX_DESCQ_EVQ_ID_LBN 24
+#define TX_DESCQ_EVQ_ID_WIDTH 12
+#define TX_DESCQ_OWNER_ID_LBN 10
+#define TX_DESCQ_OWNER_ID_WIDTH 14
+#define TX_DESCQ_LABEL_LBN 5
+#define TX_DESCQ_LABEL_WIDTH 5
+#define TX_DESCQ_SIZE_LBN 3
+#define TX_DESCQ_SIZE_WIDTH 2
+#define TX_DESCQ_SIZE_4K 3
+#define TX_DESCQ_SIZE_2K 2
+#define TX_DESCQ_SIZE_1K 1
+#define TX_DESCQ_SIZE_512 0
+#define TX_DESCQ_TYPE_LBN 1
+#define TX_DESCQ_TYPE_WIDTH 2
+
+/* Event queue pointer */
+#define EVQ_PTR_TBL_KER_A1 0x11a00
+#define EVQ_PTR_TBL_KER_B0 0xf60000
+#define EVQ_PTR_TBL_KER_P0 0x500
+#define EVQ_EN_LBN 23
+#define EVQ_EN_WIDTH 1
+#define EVQ_SIZE_LBN 20
+#define EVQ_SIZE_WIDTH 3
+#define EVQ_SIZE_32K 6
+#define EVQ_SIZE_16K 5
+#define EVQ_SIZE_8K 4
+#define EVQ_SIZE_4K 3
+#define EVQ_SIZE_2K 2
+#define EVQ_SIZE_1K 1
+#define EVQ_SIZE_512 0
+#define EVQ_BUF_BASE_ID_LBN 0
+#define EVQ_BUF_BASE_ID_WIDTH 20
+
+/* Event queue read pointer */
+#define EVQ_RPTR_REG_KER_A1 0x11b00
+#define EVQ_RPTR_REG_KER_B0 0xfa0000
+#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0)
+#define EVQ_RPTR_DWORD_LBN 0
+#define EVQ_RPTR_DWORD_WIDTH 14
+
+/* RSS indirection table */
+#define RX_RSS_INDIR_TBL_B0 0xFB0000
+#define RX_RSS_INDIR_ENT_B0_LBN 0
+#define RX_RSS_INDIR_ENT_B0_WIDTH 6
+
+/* Special buffer descriptors (full-mode) */
+#define BUF_FULL_TBL_KER_A1 0x8000
+#define BUF_FULL_TBL_KER_B0 0x800000
+#define IP_DAT_BUF_SIZE_LBN 50
+#define IP_DAT_BUF_SIZE_WIDTH 1
+#define IP_DAT_BUF_SIZE_8K 1
+#define IP_DAT_BUF_SIZE_4K 0
+#define BUF_ADR_REGION_LBN 48
+#define BUF_ADR_REGION_WIDTH 2
+#define BUF_ADR_FBUF_LBN 14
+#define BUF_ADR_FBUF_WIDTH 34
+#define BUF_OWNER_ID_FBUF_LBN 0
+#define BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* Transmit descriptor */
+#define TX_KER_PORT_LBN 63
+#define TX_KER_PORT_WIDTH 1
+#define TX_KER_CONT_LBN 62
+#define TX_KER_CONT_WIDTH 1
+#define TX_KER_BYTE_CNT_LBN 48
+#define TX_KER_BYTE_CNT_WIDTH 14
+#define TX_KER_BUF_REGION_LBN 46
+#define TX_KER_BUF_REGION_WIDTH 2
+#define TX_KER_BUF_REGION0_DECODE 0
+#define TX_KER_BUF_REGION1_DECODE 1
+#define TX_KER_BUF_REGION2_DECODE 2
+#define TX_KER_BUF_REGION3_DECODE 3
+#define TX_KER_BUF_ADR_LBN 0
+#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/* Receive descriptor */
+#define RX_KER_BUF_SIZE_LBN 48
+#define RX_KER_BUF_SIZE_WIDTH 14
+#define RX_KER_BUF_REGION_LBN 46
+#define RX_KER_BUF_REGION_WIDTH 2
+#define RX_KER_BUF_REGION0_DECODE 0
+#define RX_KER_BUF_REGION1_DECODE 1
+#define RX_KER_BUF_REGION2_DECODE 2
+#define RX_KER_BUF_REGION3_DECODE 3
+#define RX_KER_BUF_ADR_LBN 0
+#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/**************************************************************************
+ *
+ * Falcon events
+ *
+ **************************************************************************
+ */
+
+/* Event queue entries */
+#define EV_CODE_LBN 60
+#define EV_CODE_WIDTH 4
+#define RX_IP_EV_DECODE 0
+#define TX_IP_EV_DECODE 2
+#define DRIVER_EV_DECODE 5
+#define GLOBAL_EV_DECODE 6
+#define DRV_GEN_EV_DECODE 7
+#define WHOLE_EVENT_LBN 0
+#define WHOLE_EVENT_WIDTH 64
+
+/* Receive events */
+#define RX_EV_PKT_OK_LBN 56
+#define RX_EV_PKT_OK_WIDTH 1
+#define RX_EV_PAUSE_FRM_ERR_LBN 55
+#define RX_EV_PAUSE_FRM_ERR_WIDTH 1
+#define RX_EV_BUF_OWNER_ID_ERR_LBN 54
+#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define RX_EV_IF_FRAG_ERR_LBN 53
+#define RX_EV_IF_FRAG_ERR_WIDTH 1
+#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
+#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
+#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
+#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
+#define RX_EV_ETH_CRC_ERR_LBN 50
+#define RX_EV_ETH_CRC_ERR_WIDTH 1
+#define RX_EV_FRM_TRUNC_LBN 49
+#define RX_EV_FRM_TRUNC_WIDTH 1
+#define RX_EV_DRIB_NIB_LBN 48
+#define RX_EV_DRIB_NIB_WIDTH 1
+#define RX_EV_TOBE_DISC_LBN 47
+#define RX_EV_TOBE_DISC_WIDTH 1
+#define RX_EV_PKT_TYPE_LBN 44
+#define RX_EV_PKT_TYPE_WIDTH 3
+#define RX_EV_PKT_TYPE_ETH_DECODE 0
+#define RX_EV_PKT_TYPE_LLC_DECODE 1
+#define RX_EV_PKT_TYPE_JUMBO_DECODE 2
+#define RX_EV_PKT_TYPE_VLAN_DECODE 3
+#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
+#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
+#define RX_EV_HDR_TYPE_LBN 42
+#define RX_EV_HDR_TYPE_WIDTH 2
+#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
+#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
+#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
+#define RX_EV_HDR_TYPE_NON_IP_DECODE 3
+#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \
+ ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE)
+#define RX_EV_MCAST_HASH_MATCH_LBN 40
+#define RX_EV_MCAST_HASH_MATCH_WIDTH 1
+#define RX_EV_MCAST_PKT_LBN 39
+#define RX_EV_MCAST_PKT_WIDTH 1
+#define RX_EV_Q_LABEL_LBN 32
+#define RX_EV_Q_LABEL_WIDTH 5
+#define RX_EV_JUMBO_CONT_LBN 31
+#define RX_EV_JUMBO_CONT_WIDTH 1
+#define RX_EV_BYTE_CNT_LBN 16
+#define RX_EV_BYTE_CNT_WIDTH 14
+#define RX_EV_SOP_LBN 15
+#define RX_EV_SOP_WIDTH 1
+#define RX_EV_DESC_PTR_LBN 0
+#define RX_EV_DESC_PTR_WIDTH 12
+
+/* Transmit events */
+#define TX_EV_PKT_ERR_LBN 38
+#define TX_EV_PKT_ERR_WIDTH 1
+#define TX_EV_Q_LABEL_LBN 32
+#define TX_EV_Q_LABEL_WIDTH 5
+#define TX_EV_WQ_FF_FULL_LBN 15
+#define TX_EV_WQ_FF_FULL_WIDTH 1
+#define TX_EV_COMP_LBN 12
+#define TX_EV_COMP_WIDTH 1
+#define TX_EV_DESC_PTR_LBN 0
+#define TX_EV_DESC_PTR_WIDTH 12
+
+/* Driver events */
+#define DRIVER_EV_SUB_CODE_LBN 56
+#define DRIVER_EV_SUB_CODE_WIDTH 4
+#define DRIVER_EV_SUB_DATA_LBN 0
+#define DRIVER_EV_SUB_DATA_WIDTH 14
+#define TX_DESCQ_FLS_DONE_EV_DECODE 0
+#define RX_DESCQ_FLS_DONE_EV_DECODE 1
+#define EVQ_INIT_DONE_EV_DECODE 2
+#define EVQ_NOT_EN_EV_DECODE 3
+#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4
+#define SRM_UPD_DONE_EV_DECODE 5
+#define WAKE_UP_EV_DECODE 6
+#define TX_PKT_NON_TCP_UDP_DECODE 9
+#define TIMER_EV_DECODE 10
+#define RX_RECOVERY_EV_DECODE 11
+#define RX_DSC_ERROR_EV_DECODE 14
+#define TX_DSC_ERROR_EV_DECODE 15
+#define DRIVER_EV_TX_DESCQ_ID_LBN 0
+#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
+#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12
+#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
+#define DRIVER_EV_RX_DESCQ_ID_LBN 0
+#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
+#define SRM_CLR_EV_DECODE 0
+#define SRM_UPD_EV_DECODE 1
+#define SRM_ILLCLR_EV_DECODE 2
+
+/* Global events */
+#define RX_RECOVERY_B0_LBN 12
+#define RX_RECOVERY_B0_WIDTH 1
+#define XG_MNT_INTR_B0_LBN 11
+#define XG_MNT_INTR_B0_WIDTH 1
+#define RX_RECOVERY_A1_LBN 11
+#define RX_RECOVERY_A1_WIDTH 1
+#define XG_PHY_INTR_LBN 9
+#define XG_PHY_INTR_WIDTH 1
+#define G_PHY1_INTR_LBN 8
+#define G_PHY1_INTR_WIDTH 1
+#define G_PHY0_INTR_LBN 7
+#define G_PHY0_INTR_WIDTH 1
+
+/* Driver-generated test events */
+#define EVQ_MAGIC_LBN 0
+#define EVQ_MAGIC_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ *
+ */
+#define GRxGoodOct_offset 0x0
+#define GRxBadOct_offset 0x8
+#define GRxMissPkt_offset 0x10
+#define GRxFalseCRS_offset 0x14
+#define GRxPausePkt_offset 0x18
+#define GRxBadPkt_offset 0x1C
+#define GRxUcastPkt_offset 0x20
+#define GRxMcastPkt_offset 0x24
+#define GRxBcastPkt_offset 0x28
+#define GRxGoodLt64Pkt_offset 0x2C
+#define GRxBadLt64Pkt_offset 0x30
+#define GRx64Pkt_offset 0x34
+#define GRx65to127Pkt_offset 0x38
+#define GRx128to255Pkt_offset 0x3C
+#define GRx256to511Pkt_offset 0x40
+#define GRx512to1023Pkt_offset 0x44
+#define GRx1024to15xxPkt_offset 0x48
+#define GRx15xxtoJumboPkt_offset 0x4C
+#define GRxGtJumboPkt_offset 0x50
+#define GRxFcsErr64to15xxPkt_offset 0x54
+#define GRxFcsErr15xxtoJumboPkt_offset 0x58
+#define GRxFcsErrGtJumboPkt_offset 0x5C
+#define GTxGoodBadOct_offset 0x80
+#define GTxGoodOct_offset 0x88
+#define GTxSglColPkt_offset 0x90
+#define GTxMultColPkt_offset 0x94
+#define GTxExColPkt_offset 0x98
+#define GTxDefPkt_offset 0x9C
+#define GTxLateCol_offset 0xA0
+#define GTxExDefPkt_offset 0xA4
+#define GTxPausePkt_offset 0xA8
+#define GTxBadPkt_offset 0xAC
+#define GTxUcastPkt_offset 0xB0
+#define GTxMcastPkt_offset 0xB4
+#define GTxBcastPkt_offset 0xB8
+#define GTxLt64Pkt_offset 0xBC
+#define GTx64Pkt_offset 0xC0
+#define GTx65to127Pkt_offset 0xC4
+#define GTx128to255Pkt_offset 0xC8
+#define GTx256to511Pkt_offset 0xCC
+#define GTx512to1023Pkt_offset 0xD0
+#define GTx1024to15xxPkt_offset 0xD4
+#define GTx15xxtoJumboPkt_offset 0xD8
+#define GTxGtJumboPkt_offset 0xDC
+#define GTxNonTcpUdpPkt_offset 0xE0
+#define GTxMacSrcErrPkt_offset 0xE4
+#define GTxIpSrcErrPkt_offset 0xE8
+#define GDmaDone_offset 0xEC
+
+#define XgRxOctets_offset 0x0
+#define XgRxOctets_WIDTH 48
+#define XgRxOctetsOK_offset 0x8
+#define XgRxOctetsOK_WIDTH 48
+#define XgRxPkts_offset 0x10
+#define XgRxPkts_WIDTH 32
+#define XgRxPktsOK_offset 0x14
+#define XgRxPktsOK_WIDTH 32
+#define XgRxBroadcastPkts_offset 0x18
+#define XgRxBroadcastPkts_WIDTH 32
+#define XgRxMulticastPkts_offset 0x1C
+#define XgRxMulticastPkts_WIDTH 32
+#define XgRxUnicastPkts_offset 0x20
+#define XgRxUnicastPkts_WIDTH 32
+#define XgRxUndersizePkts_offset 0x24
+#define XgRxUndersizePkts_WIDTH 32
+#define XgRxOversizePkts_offset 0x28
+#define XgRxOversizePkts_WIDTH 32
+#define XgRxJabberPkts_offset 0x2C
+#define XgRxJabberPkts_WIDTH 32
+#define XgRxUndersizeFCSerrorPkts_offset 0x30
+#define XgRxUndersizeFCSerrorPkts_WIDTH 32
+#define XgRxDropEvents_offset 0x34
+#define XgRxDropEvents_WIDTH 32
+#define XgRxFCSerrorPkts_offset 0x38
+#define XgRxFCSerrorPkts_WIDTH 32
+#define XgRxAlignError_offset 0x3C
+#define XgRxAlignError_WIDTH 32
+#define XgRxSymbolError_offset 0x40
+#define XgRxSymbolError_WIDTH 32
+#define XgRxInternalMACError_offset 0x44
+#define XgRxInternalMACError_WIDTH 32
+#define XgRxControlPkts_offset 0x48
+#define XgRxControlPkts_WIDTH 32
+#define XgRxPausePkts_offset 0x4C
+#define XgRxPausePkts_WIDTH 32
+#define XgRxPkts64Octets_offset 0x50
+#define XgRxPkts64Octets_WIDTH 32
+#define XgRxPkts65to127Octets_offset 0x54
+#define XgRxPkts65to127Octets_WIDTH 32
+#define XgRxPkts128to255Octets_offset 0x58
+#define XgRxPkts128to255Octets_WIDTH 32
+#define XgRxPkts256to511Octets_offset 0x5C
+#define XgRxPkts256to511Octets_WIDTH 32
+#define XgRxPkts512to1023Octets_offset 0x60
+#define XgRxPkts512to1023Octets_WIDTH 32
+#define XgRxPkts1024to15xxOctets_offset 0x64
+#define XgRxPkts1024to15xxOctets_WIDTH 32
+#define XgRxPkts15xxtoMaxOctets_offset 0x68
+#define XgRxPkts15xxtoMaxOctets_WIDTH 32
+#define XgRxLengthError_offset 0x6C
+#define XgRxLengthError_WIDTH 32
+#define XgTxPkts_offset 0x80
+#define XgTxPkts_WIDTH 32
+#define XgTxOctets_offset 0x88
+#define XgTxOctets_WIDTH 48
+#define XgTxMulticastPkts_offset 0x90
+#define XgTxMulticastPkts_WIDTH 32
+#define XgTxBroadcastPkts_offset 0x94
+#define XgTxBroadcastPkts_WIDTH 32
+#define XgTxUnicastPkts_offset 0x98
+#define XgTxUnicastPkts_WIDTH 32
+#define XgTxControlPkts_offset 0x9C
+#define XgTxControlPkts_WIDTH 32
+#define XgTxPausePkts_offset 0xA0
+#define XgTxPausePkts_WIDTH 32
+#define XgTxPkts64Octets_offset 0xA4
+#define XgTxPkts64Octets_WIDTH 32
+#define XgTxPkts65to127Octets_offset 0xA8
+#define XgTxPkts65to127Octets_WIDTH 32
+#define XgTxPkts128to255Octets_offset 0xAC
+#define XgTxPkts128to255Octets_WIDTH 32
+#define XgTxPkts256to511Octets_offset 0xB0
+#define XgTxPkts256to511Octets_WIDTH 32
+#define XgTxPkts512to1023Octets_offset 0xB4
+#define XgTxPkts512to1023Octets_WIDTH 32
+#define XgTxPkts1024to15xxOctets_offset 0xB8
+#define XgTxPkts1024to15xxOctets_WIDTH 32
+#define XgTxPkts1519toMaxOctets_offset 0xBC
+#define XgTxPkts1519toMaxOctets_WIDTH 32
+#define XgTxUndersizePkts_offset 0xC0
+#define XgTxUndersizePkts_WIDTH 32
+#define XgTxOversizePkts_offset 0xC4
+#define XgTxOversizePkts_WIDTH 32
+#define XgTxNonTcpUdpPkt_offset 0xC8
+#define XgTxNonTcpUdpPkt_WIDTH 16
+#define XgTxMacSrcErrPkt_offset 0xCC
+#define XgTxMacSrcErrPkt_WIDTH 16
+#define XgTxIpSrcErrPkt_offset 0xD0
+#define XgTxIpSrcErrPkt_WIDTH 16
+#define XgDmaDone_offset 0xD4
+
+#define FALCON_STATS_NOT_DONE 0x00000000
+#define FALCON_STATS_DONE 0xffffffff
+
+/* Interrupt status register bits */
+#define FATAL_INT_LBN 64
+#define FATAL_INT_WIDTH 1
+#define INT_EVQS_LBN 40
+#define INT_EVQS_WIDTH 4
+
+/**************************************************************************
+ *
+ * Falcon non-volatile configuration
+ *
+ **************************************************************************
+ */
+
+/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
+struct falcon_nvconfig_board_v2 {
+ __le16 nports;
+ u8 port0_phy_addr;
+ u8 port0_phy_type;
+ u8 port1_phy_addr;
+ u8 port1_phy_type;
+ __le16 asic_sub_revision;
+ __le16 board_revision;
+} __attribute__ ((packed));
+
+#define NVCONFIG_BASE 0x300
+#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
+struct falcon_nvconfig {
+ efx_oword_t ee_vpd_cfg_reg; /* 0x300 */
+ u8 mac_address[2][8]; /* 0x310 */
+ efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */
+ efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */
+ efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */
+ efx_oword_t hw_init_reg; /* 0x350 */
+ efx_oword_t nic_stat_reg; /* 0x360 */
+ efx_oword_t glb_ctl_reg; /* 0x370 */
+ efx_oword_t srm_cfg_reg; /* 0x380 */
+ efx_oword_t spare_reg; /* 0x390 */
+ __le16 board_magic_num; /* 0x3A0 */
+ __le16 board_struct_ver;
+ __le16 board_checksum;
+ struct falcon_nvconfig_board_v2 board_v2;
+} __attribute__ ((packed));
+
+#endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
new file mode 100644
index 00000000000..ea08184ddfa
--- /dev/null
+++ b/drivers/net/sfc/falcon_io.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_IO_H
+#define EFX_FALCON_IO_H
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Falcon hardware access
+ *
+ **************************************************************************
+ *
+ * Notes on locking strategy:
+ *
+ * Most Falcon registers require 16-byte (or 8-byte, for SRAM
+ * registers) atomic writes which necessitates locking.
+ * Under normal operation few writes to the Falcon BAR are made and these
+ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
+ * cased to allow 4-byte (hence lockless) accesses.
+ *
+ * It *is* safe to write to these 4-byte registers in the middle of an
+ * access to an 8-byte or 16-byte register. We therefore use a
+ * spinlock to protect accesses to the larger registers, but no locks
+ * for the 4-byte registers.
+ *
+ * A write barrier is needed to ensure that DW3 is written after DW0/1/2
+ * due to the way the 16byte registers are "collected" in the Falcon BIU
+ *
+ * We also lock when carrying out reads, to ensure consistency of the
+ * data (made possible since the BIU reads all 128 bits into a cache).
+ * Reads are very rare, so this isn't a significant performance
+ * impact. (Most data transferred from NIC to host is DMAed directly
+ * into host memory).
+ *
+ * I/O BAR access uses locks for both reads and writes (but is only provided
+ * for testing purposes).
+ */
+
+/* Special buffer descriptors (Falcon SRAM) */
+#define BUF_TBL_KER_A1 0x18000
+#define BUF_TBL_KER_B0 0x800000
+
+
+#if BITS_PER_LONG == 64
+#define FALCON_USE_QWORD_IO 1
+#endif
+
+#define _falcon_writeq(efx, value, reg) \
+ __raw_writeq((__force u64) (value), (efx)->membase + (reg))
+#define _falcon_writel(efx, value, reg) \
+ __raw_writel((__force u32) (value), (efx)->membase + (reg))
+#define _falcon_readq(efx, reg) \
+ ((__force __le64) __raw_readq((efx)->membase + (reg)))
+#define _falcon_readl(efx, reg) \
+ ((__force __le32) __raw_readl((efx)->membase + (reg)))
+
+/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
+static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags;
+
+ EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ _falcon_writeq(efx, value->u64[0], reg + 0);
+ wmb();
+ _falcon_writeq(efx, value->u64[1], reg + 8);
+#else
+ _falcon_writel(efx, value->u32[0], reg + 0);
+ _falcon_writel(efx, value->u32[1], reg + 4);
+ _falcon_writel(efx, value->u32[2], reg + 8);
+ wmb();
+ _falcon_writel(efx, value->u32[3], reg + 12);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
+static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
+ unsigned long flags;
+
+ EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
+ reg, EFX_QWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ _falcon_writeq(efx, value->u64[0], reg + 0);
+#else
+ _falcon_writel(efx, value->u32[0], reg + 0);
+ wmb();
+ _falcon_writel(efx, value->u32[1], reg + 4);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write dword to Falcon register that allows partial writes
+ *
+ * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
+ * TX_DESC_UPD_REG) can be written to as a single dword. This allows
+ * for lockless writes.
+ */
+static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+
+ /* No lock required */
+ _falcon_writel(efx, value->u32[0], reg);
+}
+
+/* Read from a Falcon register
+ *
+ * This reads an entire 16-byte Falcon register in one go, locking as
+ * appropriate. It is essential to read the first dword first, as this
+ * prompts Falcon to load the current value into the shadow register.
+ */
+static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ value->u32[0] = _falcon_readl(efx, reg + 0);
+ rmb();
+ value->u32[1] = _falcon_readl(efx, reg + 4);
+ value->u32[2] = _falcon_readl(efx, reg + 8);
+ value->u32[3] = _falcon_readl(efx, reg + 12);
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+}
+
+/* This reads an 8-byte Falcon SRAM entry in one go. */
+static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ value->u64[0] = _falcon_readq(efx, reg + 0);
+#else
+ value->u32[0] = _falcon_readl(efx, reg + 0);
+ rmb();
+ value->u32[1] = _falcon_readl(efx, reg + 4);
+#endif
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
+ reg, EFX_QWORD_VAL(*value));
+}
+
+/* Read dword from Falcon register that allows partial writes (sic) */
+static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ value->u32[0] = _falcon_readl(efx, reg);
+ EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+}
+
+/* Write to a register forming part of a table */
+static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Read to a register forming part of a table */
+static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Write to a dword register forming part of a table */
+static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Page-mapped register block size */
+#define FALCON_PAGE_BLOCK_SIZE 0x2000
+
+/* Calculate offset to page-mapped register block */
+#define FALCON_PAGED_REG(page, reg) \
+ ((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
+
+/* As for falcon_write(), but for a page-mapped register. */
+static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
+}
+
+/* As for falcon_writel(), but for a page-mapped register. */
+static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
+}
+
+/* Write dword to Falcon page-mapped register with an extra lock.
+ *
+ * As for falcon_writel_page(), but for a register that suffers from
+ * SFC bug 3181. Take out a lock so the BIU collector cannot be
+ * confused. */
+static inline void falcon_writel_page_locked(struct efx_nic *efx,
+ efx_dword_t *value,
+ unsigned int reg,
+ unsigned int page)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+#endif /* EFX_FALCON_IO_H */
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
new file mode 100644
index 00000000000..aa7521b24a5
--- /dev/null
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -0,0 +1,585 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "mac.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "boards.h"
+#include "workarounds.h"
+
+/**************************************************************************
+ *
+ * MAC register access
+ *
+ **************************************************************************/
+
+/* Offset of an XMAC register within Falcon */
+#define FALCON_XMAC_REG(mac_reg) \
+ (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
+
+void falcon_xmac_writel(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg)
+{
+ efx_oword_t temp;
+
+ EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
+ falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
+}
+
+void falcon_xmac_readl(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg)
+{
+ efx_oword_t temp;
+
+ falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
+ EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
+}
+
+/**************************************************************************
+ *
+ * MAC operations
+ *
+ *************************************************************************/
+static int falcon_reset_xmac(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int count;
+
+ EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
+ falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+
+ for (count = 0; count < 10000; count++) { /* wait upto 100ms */
+ falcon_xmac_readl(efx, &reg, XM_GLB_CFG_REG_MAC);
+ if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
+ return 0;
+ udelay(10);
+ }
+
+ EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
+ return -ETIMEDOUT;
+}
+
+/* Configure the XAUI driver that is an output from Falcon */
+static void falcon_setup_xaui(struct efx_nic *efx)
+{
+ efx_dword_t sdctl, txdrv;
+
+ /* Move the XAUI into low power, unless there is no PHY, in
+ * which case the XAUI will have to drive a cable. */
+ if (efx->phy_type == PHY_TYPE_NONE)
+ return;
+
+ falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
+ falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
+
+ EFX_POPULATE_DWORD_8(txdrv,
+ XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+ XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+ falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
+}
+
+static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ EFX_ZERO_DWORD(reg);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+}
+
+static int _falcon_reset_xaui_a(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ falcon_hold_xaui_in_rst(efx);
+ falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
+
+ /* Follow the RAMBUS XAUI data reset sequencing
+ * Channels A and B first: power down, reset PLL, reset, clear
+ */
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Channels C and D: power down, reset PLL, reset, clear */
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Setup XAUI */
+ falcon_setup_xaui(efx);
+ udelay(10);
+
+ /* Take XGXS out of reset */
+ EFX_ZERO_DWORD(reg);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ return 0;
+}
+
+static int _falcon_reset_xaui_b(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int count;
+
+ EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+
+ /* Give some time for the link to establish */
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
+ if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
+ falcon_setup_xaui(efx);
+ return 0;
+ }
+ udelay(10);
+ }
+ EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
+ return -ETIMEDOUT;
+}
+
+int falcon_reset_xaui(struct efx_nic *efx)
+{
+ int rc;
+
+ if (EFX_WORKAROUND_9388(efx)) {
+ falcon_hold_xaui_in_rst(efx);
+ efx->phy_op->reset_xaui(efx);
+ rc = _falcon_reset_xaui_a(efx);
+ } else {
+ rc = _falcon_reset_xaui_b(efx);
+ }
+ return rc;
+}
+
+static int falcon_xgmii_status(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return 1;
+
+ /* The ISR latches, so clear it and re-read */
+ falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+ falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+
+ if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
+ EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
+ EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
+ return 0;
+ }
+
+ return 1;
+}
+
+static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
+{
+ efx_dword_t reg;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ /* Flush the ISR */
+ if (enable)
+ falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+
+ EFX_POPULATE_DWORD_2(reg,
+ XM_MSK_RMTFLT, !enable,
+ XM_MSK_LCLFLT, !enable);
+ falcon_xmac_writel(efx, &reg, XM_MGT_INT_MSK_REG_MAC_B0);
+}
+
+int falcon_init_xmac(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Initialize the PHY first so the clock is around */
+ rc = efx->phy_op->init(efx);
+ if (rc)
+ goto fail1;
+
+ rc = falcon_reset_xaui(efx);
+ if (rc)
+ goto fail2;
+
+ /* Wait again. Give the PHY and MAC time to come back */
+ schedule_timeout_uninterruptible(HZ / 10);
+
+ rc = falcon_reset_xmac(efx);
+ if (rc)
+ goto fail2;
+
+ falcon_mask_status_intr(efx, 1);
+ return 0;
+
+ fail2:
+ efx->phy_op->fini(efx);
+ fail1:
+ return rc;
+}
+
+int falcon_xaui_link_ok(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int align_done, sync_status, link_ok = 0;
+
+ /* Read link status */
+ falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+
+ align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
+ sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
+ if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
+ link_ok = 1;
+
+ /* Clear link status ready for next read */
+ EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
+ EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
+ EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
+ falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
+
+ /* If the link is up, then check the phy side of the xaui link
+ * (error conditions from the wire side propoagate back through
+ * the phy to the xaui side). */
+ if (efx->link_up && link_ok) {
+ int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
+ if (has_phyxs)
+ link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
+ }
+
+ /* If the PHY and XAUI links are up, then check the mac's xgmii
+ * fault state */
+ if (efx->link_up && link_ok)
+ link_ok = falcon_xgmii_status(efx);
+
+ return link_ok;
+}
+
+static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+{
+ unsigned int max_frame_len;
+ efx_dword_t reg;
+ int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+
+ /* Configure MAC - cut-thru mode is hard wired on */
+ EFX_POPULATE_DWORD_3(reg,
+ XM_RX_JUMBO_MODE, 1,
+ XM_TX_STAT_EN, 1,
+ XM_RX_STAT_EN, 1);
+ falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+
+ /* Configure TX */
+ EFX_POPULATE_DWORD_6(reg,
+ XM_TXEN, 1,
+ XM_TX_PRMBL, 1,
+ XM_AUTO_PAD, 1,
+ XM_TXCRC, 1,
+ XM_FCNTL, 1,
+ XM_IPG, 0x3);
+ falcon_xmac_writel(efx, &reg, XM_TX_CFG_REG_MAC);
+
+ /* Configure RX */
+ EFX_POPULATE_DWORD_5(reg,
+ XM_RXEN, 1,
+ XM_AUTO_DEPAD, 0,
+ XM_ACPT_ALL_MCAST, 1,
+ XM_ACPT_ALL_UCAST, efx->promiscuous,
+ XM_PASS_CRC_ERR, 1);
+ falcon_xmac_writel(efx, &reg, XM_RX_CFG_REG_MAC);
+
+ /* Set frame length */
+ max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
+ EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
+ falcon_xmac_writel(efx, &reg, XM_RX_PARAM_REG_MAC);
+ EFX_POPULATE_DWORD_2(reg,
+ XM_MAX_TX_FRM_SIZE, max_frame_len,
+ XM_TX_JUMBO_MODE, 1);
+ falcon_xmac_writel(efx, &reg, XM_TX_PARAM_REG_MAC);
+
+ EFX_POPULATE_DWORD_2(reg,
+ XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
+ XM_DIS_FCNTL, rx_fc ? 0 : 1);
+ falcon_xmac_writel(efx, &reg, XM_FC_REG_MAC);
+
+ /* Set MAC address */
+ EFX_POPULATE_DWORD_4(reg,
+ XM_ADR_0, efx->net_dev->dev_addr[0],
+ XM_ADR_1, efx->net_dev->dev_addr[1],
+ XM_ADR_2, efx->net_dev->dev_addr[2],
+ XM_ADR_3, efx->net_dev->dev_addr[3]);
+ falcon_xmac_writel(efx, &reg, XM_ADR_LO_REG_MAC);
+ EFX_POPULATE_DWORD_2(reg,
+ XM_ADR_4, efx->net_dev->dev_addr[4],
+ XM_ADR_5, efx->net_dev->dev_addr[5]);
+ falcon_xmac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
+}
+
+/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
+ * to come back up. Bash it until it comes back up */
+static int falcon_check_xaui_link_up(struct efx_nic *efx)
+{
+ int max_tries, tries;
+ tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
+ max_tries = tries;
+
+ if (efx->phy_type == PHY_TYPE_NONE)
+ return 0;
+
+ while (tries) {
+ if (falcon_xaui_link_ok(efx))
+ return 1;
+
+ EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
+ __func__, tries);
+ (void) falcon_reset_xaui(efx);
+ udelay(200);
+ tries--;
+ }
+
+ EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n",
+ max_tries);
+ return 0;
+}
+
+void falcon_reconfigure_xmac(struct efx_nic *efx)
+{
+ int xaui_link_ok;
+
+ falcon_mask_status_intr(efx, 0);
+
+ falcon_deconfigure_mac_wrapper(efx);
+ efx->phy_op->reconfigure(efx);
+ falcon_reconfigure_xmac_core(efx);
+ falcon_reconfigure_mac_wrapper(efx);
+
+ /* Ensure XAUI link is up */
+ xaui_link_ok = falcon_check_xaui_link_up(efx);
+
+ if (xaui_link_ok && efx->link_up)
+ falcon_mask_status_intr(efx, 1);
+}
+
+void falcon_fini_xmac(struct efx_nic *efx)
+{
+ /* Isolate the MAC - PHY */
+ falcon_deconfigure_mac_wrapper(efx);
+
+ /* Potentially power down the PHY */
+ efx->phy_op->fini(efx);
+}
+
+void falcon_update_stats_xmac(struct efx_nic *efx)
+{
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ int rc;
+
+ rc = falcon_dma_stats(efx, XgDmaDone_offset);
+ if (rc)
+ return;
+
+ /* Update MAC stats from DMAed values */
+ FALCON_STAT(efx, XgRxOctets, rx_bytes);
+ FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
+ FALCON_STAT(efx, XgRxPkts, rx_packets);
+ FALCON_STAT(efx, XgRxPktsOK, rx_good);
+ FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
+ FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
+ FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
+ FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
+ FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
+ FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
+ FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
+ FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
+ FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
+ FALCON_STAT(efx, XgRxAlignError, rx_align_error);
+ FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
+ FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
+ FALCON_STAT(efx, XgRxControlPkts, rx_control);
+ FALCON_STAT(efx, XgRxPausePkts, rx_pause);
+ FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
+ FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
+ FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
+ FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
+ FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
+ FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
+ FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
+ FALCON_STAT(efx, XgRxLengthError, rx_length_error);
+ FALCON_STAT(efx, XgTxPkts, tx_packets);
+ FALCON_STAT(efx, XgTxOctets, tx_bytes);
+ FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
+ FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
+ FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
+ FALCON_STAT(efx, XgTxControlPkts, tx_control);
+ FALCON_STAT(efx, XgTxPausePkts, tx_pause);
+ FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
+ FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
+ FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
+ FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
+ FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
+ FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
+ FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
+ FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
+ FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
+ FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
+ FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
+ FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);
+
+ /* Update derived statistics */
+ mac_stats->tx_good_bytes =
+ (mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
+ mac_stats->rx_bad_bytes =
+ (mac_stats->rx_bytes - mac_stats->rx_good_bytes);
+}
+
+#define EFX_XAUI_RETRAIN_MAX 8
+
+int falcon_check_xmac(struct efx_nic *efx)
+{
+ unsigned xaui_link_ok;
+ int rc;
+
+ falcon_mask_status_intr(efx, 0);
+ xaui_link_ok = falcon_xaui_link_ok(efx);
+
+ if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
+ (void) falcon_reset_xaui(efx);
+
+ /* Call the PHY check_hw routine */
+ rc = efx->phy_op->check_hw(efx);
+
+ /* Unmask interrupt if everything was (and still is) ok */
+ if (xaui_link_ok && efx->link_up)
+ falcon_mask_status_intr(efx, 1);
+
+ return rc;
+}
+
+/* Simulate a PHY event */
+void falcon_xmac_sim_phy_event(struct efx_nic *efx)
+{
+ efx_qword_t phy_event;
+
+ EFX_POPULATE_QWORD_2(phy_event,
+ EV_CODE, GLOBAL_EV_DECODE,
+ XG_PHY_INTR, 1);
+ falcon_generate_event(&efx->channel[0], &phy_event);
+}
+
+int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ mdio_clause45_get_settings(efx, ecmd);
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->phy_address = efx->mii.phy_id;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->duplex = DUPLEX_FULL;
+ return 0;
+}
+
+int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ if (ecmd->transceiver != XCVR_INTERNAL)
+ return -EINVAL;
+ if (ecmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (ecmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ return mdio_clause45_set_settings(efx, ecmd);
+}
+
+
+int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
+{
+ int reset;
+
+ if (flow_control & EFX_FC_AUTO) {
+ EFX_LOG(efx, "10G does not support flow control "
+ "autonegotiation\n");
+ return -EINVAL;
+ }
+
+ if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
+ return -EINVAL;
+
+ /* TX flow control may automatically turn itself off if the
+ * link partner (intermittently) stops responding to pause
+ * frames. There isn't any indication that this has happened,
+ * so the best we do is leave it up to the user to spot this
+ * and fix it be cycling transmit flow control on this end. */
+ reset = ((flow_control & EFX_FC_TX) &&
+ !(efx->flow_control & EFX_FC_TX));
+ if (EFX_WORKAROUND_11482(efx) && reset) {
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ /* Recover by resetting the EM block */
+ if (efx->link_up)
+ falcon_drain_tx_fifo(efx);
+ } else {
+ /* Schedule a reset to recover */
+ efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
+ }
+ }
+
+ efx->flow_control = flow_control;
+
+ return 0;
+}
diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h
new file mode 100644
index 00000000000..d25bbd1297f
--- /dev/null
+++ b/drivers/net/sfc/gmii.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_GMII_H
+#define EFX_GMII_H
+
+/*
+ * GMII interface
+ */
+
+#include <linux/mii.h>
+
+/* GMII registers, excluding registers already defined as MII
+ * registers in mii.h
+ */
+#define GMII_IER 0x12 /* Interrupt enable register */
+#define GMII_ISR 0x13 /* Interrupt status register */
+
+/* Interrupt enable register */
+#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
+#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
+#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
+#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */
+#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
+#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */
+#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */
+#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
+#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
+#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
+#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
+#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */
+#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
+#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
+#define IER_JABBER 0x0001 /* Bit 0 - jabber */
+
+/* Interrupt status register */
+#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
+#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
+#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
+#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */
+#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
+#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */
+#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */
+#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
+#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
+#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
+#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
+#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */
+#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
+#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
+#define ISR_JABBER 0x0001 /* Bit 0 - jabber */
+
+/* Logically extended advertisement register */
+#define GM_ADVERTISE_SLCT ADVERTISE_SLCT
+#define GM_ADVERTISE_CSMA ADVERTISE_CSMA
+#define GM_ADVERTISE_10HALF ADVERTISE_10HALF
+#define GM_ADVERTISE_1000XFULL ADVERTISE_1000XFULL
+#define GM_ADVERTISE_10FULL ADVERTISE_10FULL
+#define GM_ADVERTISE_1000XHALF ADVERTISE_1000XHALF
+#define GM_ADVERTISE_100HALF ADVERTISE_100HALF
+#define GM_ADVERTISE_1000XPAUSE ADVERTISE_1000XPAUSE
+#define GM_ADVERTISE_100FULL ADVERTISE_100FULL
+#define GM_ADVERTISE_1000XPSE_ASYM ADVERTISE_1000XPSE_ASYM
+#define GM_ADVERTISE_100BASE4 ADVERTISE_100BASE4
+#define GM_ADVERTISE_PAUSE_CAP ADVERTISE_PAUSE_CAP
+#define GM_ADVERTISE_PAUSE_ASYM ADVERTISE_PAUSE_ASYM
+#define GM_ADVERTISE_RESV ADVERTISE_RESV
+#define GM_ADVERTISE_RFAULT ADVERTISE_RFAULT
+#define GM_ADVERTISE_LPACK ADVERTISE_LPACK
+#define GM_ADVERTISE_NPAGE ADVERTISE_NPAGE
+#define GM_ADVERTISE_1000FULL (ADVERTISE_1000FULL << 8)
+#define GM_ADVERTISE_1000HALF (ADVERTISE_1000HALF << 8)
+#define GM_ADVERTISE_1000 (GM_ADVERTISE_1000FULL | \
+ GM_ADVERTISE_1000HALF)
+#define GM_ADVERTISE_FULL (GM_ADVERTISE_1000FULL | \
+ ADVERTISE_FULL)
+#define GM_ADVERTISE_ALL (GM_ADVERTISE_1000FULL | \
+ GM_ADVERTISE_1000HALF | \
+ ADVERTISE_ALL)
+
+/* Logically extended link partner ability register */
+#define GM_LPA_SLCT LPA_SLCT
+#define GM_LPA_10HALF LPA_10HALF
+#define GM_LPA_1000XFULL LPA_1000XFULL
+#define GM_LPA_10FULL LPA_10FULL
+#define GM_LPA_1000XHALF LPA_1000XHALF
+#define GM_LPA_100HALF LPA_100HALF
+#define GM_LPA_1000XPAUSE LPA_1000XPAUSE
+#define GM_LPA_100FULL LPA_100FULL
+#define GM_LPA_1000XPAUSE_ASYM LPA_1000XPAUSE_ASYM
+#define GM_LPA_100BASE4 LPA_100BASE4
+#define GM_LPA_PAUSE_CAP LPA_PAUSE_CAP
+#define GM_LPA_PAUSE_ASYM LPA_PAUSE_ASYM
+#define GM_LPA_RESV LPA_RESV
+#define GM_LPA_RFAULT LPA_RFAULT
+#define GM_LPA_LPACK LPA_LPACK
+#define GM_LPA_NPAGE LPA_NPAGE
+#define GM_LPA_1000FULL (LPA_1000FULL << 6)
+#define GM_LPA_1000HALF (LPA_1000HALF << 6)
+#define GM_LPA_10000FULL 0x00040000
+#define GM_LPA_10000HALF 0x00080000
+#define GM_LPA_DUPLEX (GM_LPA_1000FULL | GM_LPA_10000FULL \
+ | LPA_DUPLEX)
+#define GM_LPA_10 (LPA_10FULL | LPA_10HALF)
+#define GM_LPA_100 LPA_100
+#define GM_LPA_1000 (GM_LPA_1000FULL | GM_LPA_1000HALF)
+#define GM_LPA_10000 (GM_LPA_10000FULL | GM_LPA_10000HALF)
+
+/* Retrieve GMII autonegotiation advertised abilities
+ *
+ * The MII advertisment register (MII_ADVERTISE) is logically extended
+ * to include advertisement bits ADVERTISE_1000FULL and
+ * ADVERTISE_1000HALF from MII_CTRL1000. The result can be tested
+ * against the GM_ADVERTISE_xxx constants.
+ */
+static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
+{
+ unsigned int advertise;
+ unsigned int ctrl1000;
+
+ advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
+ ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
+ return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
+}
+
+/* Retrieve GMII autonegotiation link partner abilities
+ *
+ * The MII link partner ability register (MII_LPA) is logically
+ * extended by adding bits LPA_1000HALF and LPA_1000FULL from
+ * MII_STAT1000. The result can be tested against the GM_LPA_xxx
+ * constants.
+ */
+static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
+{
+ unsigned int lpa;
+ unsigned int stat1000;
+
+ lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
+ stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
+ return (((stat1000 << 6) & GM_LPA_1000) | lpa);
+}
+
+/* Calculate GMII autonegotiated link technology
+ *
+ * "negotiated" should be the result of gmii_advertised() logically
+ * ANDed with the result of gmii_lpa().
+ *
+ * "tech" will be negotiated with the unused bits masked out. For
+ * example, if both ends of the link are capable of both
+ * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
+ * out.
+ */
+static inline unsigned int gmii_nway_result(unsigned int negotiated)
+{
+ unsigned int other_bits;
+
+ /* Mask out the speed and duplexity bits */
+ other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
+
+ if (negotiated & GM_LPA_1000FULL)
+ return (other_bits | GM_LPA_1000FULL);
+ else if (negotiated & GM_LPA_1000HALF)
+ return (other_bits | GM_LPA_1000HALF);
+ else
+ return (other_bits | mii_nway_result(negotiated));
+}
+
+/* Calculate GMII non-autonegotiated link technology
+ *
+ * This provides an equivalent to gmii_nway_result for the case when
+ * autonegotiation is disabled.
+ */
+static inline unsigned int gmii_forced_result(unsigned int bmcr)
+{
+ unsigned int result;
+ int full_duplex;
+
+ full_duplex = bmcr & BMCR_FULLDPLX;
+ if (bmcr & BMCR_SPEED1000)
+ result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
+ else if (bmcr & BMCR_SPEED100)
+ result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
+ else
+ result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
+ return result;
+}
+
+#endif /* EFX_GMII_H */
diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c
new file mode 100644
index 00000000000..b6c62d0ed9c
--- /dev/null
+++ b/drivers/net/sfc/i2c-direct.c
@@ -0,0 +1,381 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "i2c-direct.h"
+
+/*
+ * I2C data (SDA) and clock (SCL) line read/writes with appropriate
+ * delays.
+ */
+
+static inline void setsda(struct efx_i2c_interface *i2c, int state)
+{
+ udelay(i2c->op->udelay);
+ i2c->sda = state;
+ i2c->op->setsda(i2c);
+ udelay(i2c->op->udelay);
+}
+
+static inline void setscl(struct efx_i2c_interface *i2c, int state)
+{
+ udelay(i2c->op->udelay);
+ i2c->scl = state;
+ i2c->op->setscl(i2c);
+ udelay(i2c->op->udelay);
+}
+
+static inline int getsda(struct efx_i2c_interface *i2c)
+{
+ int sda;
+
+ udelay(i2c->op->udelay);
+ sda = i2c->op->getsda(i2c);
+ udelay(i2c->op->udelay);
+ return sda;
+}
+
+static inline int getscl(struct efx_i2c_interface *i2c)
+{
+ int scl;
+
+ udelay(i2c->op->udelay);
+ scl = i2c->op->getscl(i2c);
+ udelay(i2c->op->udelay);
+ return scl;
+}
+
+/*
+ * I2C low-level protocol operations
+ *
+ */
+
+static inline void i2c_release(struct efx_i2c_interface *i2c)
+{
+ EFX_WARN_ON_PARANOID(!i2c->scl);
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ /* Devices may time out if operations do not end */
+ setscl(i2c, 1);
+ setsda(i2c, 1);
+ EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
+ EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
+}
+
+static inline void i2c_start(struct efx_i2c_interface *i2c)
+{
+ /* We may be restarting immediately after a {send,recv}_bit,
+ * so SCL will not necessarily already be high.
+ */
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ setscl(i2c, 1);
+ setsda(i2c, 0);
+ setscl(i2c, 0);
+ setsda(i2c, 1);
+}
+
+static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
+{
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ setsda(i2c, bit);
+ setscl(i2c, 1);
+ setscl(i2c, 0);
+ setsda(i2c, 1);
+}
+
+static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
+{
+ int bit;
+
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ setscl(i2c, 1);
+ bit = getsda(i2c);
+ setscl(i2c, 0);
+ return bit;
+}
+
+static inline void i2c_stop(struct efx_i2c_interface *i2c)
+{
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ setsda(i2c, 0);
+ setscl(i2c, 1);
+ setsda(i2c, 1);
+}
+
+/*
+ * I2C mid-level protocol operations
+ *
+ */
+
+/* Sends a byte via the I2C bus and checks for an acknowledgement from
+ * the slave device.
+ */
+static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
+{
+ int i;
+
+ /* Send byte */
+ for (i = 0; i < 8; i++) {
+ i2c_send_bit(i2c, !!(byte & 0x80));
+ byte <<= 1;
+ }
+
+ /* Check for acknowledgement from slave */
+ return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
+}
+
+/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
+static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
+{
+ u8 value = 0;
+ int i;
+
+ /* Receive byte */
+ for (i = 0; i < 8; i++)
+ value = (value << 1) | i2c_recv_bit(i2c);
+
+ /* Send ACK/NACK */
+ i2c_send_bit(i2c, (ack ? 0 : 1));
+
+ return value;
+}
+
+/* Calculate command byte for a read operation */
+static inline u8 i2c_read_cmd(u8 device_id)
+{
+ return ((device_id << 1) | 1);
+}
+
+/* Calculate command byte for a write operation */
+static inline u8 i2c_write_cmd(u8 device_id)
+{
+ return ((device_id << 1) | 0);
+}
+
+int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
+{
+ int rc;
+
+ /* If someone is driving the bus low we just give up. */
+ if (getsda(i2c) == 0 || getscl(i2c) == 0) {
+ EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
+ " Giving up.\n", __func__);
+ return -EFAULT;
+ }
+
+ /* Pretend to initiate a device write */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* This performs a fast read of one or more consecutive bytes from an
+ * I2C device. Not all devices support consecutive reads of more than
+ * one byte; for these devices use efx_i2c_read() instead.
+ */
+int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(data == NULL);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device and starting offset */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+ rc = i2c_send_byte(i2c, offset);
+ if (rc)
+ goto out;
+
+ /* Read data from device */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
+ if (rc)
+ goto out;
+ for (i = 0; i < (len - 1); i++)
+ /* Read and acknowledge all but the last byte */
+ data[i] = i2c_recv_byte(i2c, 1);
+ /* Read last byte with no acknowledgement */
+ data[i] = i2c_recv_byte(i2c, 0);
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* This performs a fast write of one or more consecutive bytes to an
+ * I2C device. Not all devices support consecutive writes of more
+ * than one byte; for these devices use efx_i2c_write() instead.
+ */
+int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device and starting offset */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+ rc = i2c_send_byte(i2c, offset);
+ if (rc)
+ goto out;
+
+ /* Write data to device */
+ for (i = 0; i < len; i++) {
+ rc = i2c_send_byte(i2c, data[i]);
+ if (rc)
+ goto out;
+ }
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* I2C byte-by-byte read */
+int efx_i2c_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ int rc;
+
+ /* i2c_fast_read with length 1 is a single byte read */
+ for (; len > 0; offset++, data++, len--) {
+ rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/* I2C byte-by-byte write */
+int efx_i2c_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, const u8 *data, unsigned int len)
+{
+ int rc;
+
+ /* i2c_fast_write with length 1 is a single byte write */
+ for (; len > 0; offset++, data++, len--) {
+ rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
+ if (rc)
+ return rc;
+ mdelay(i2c->op->mdelay);
+ }
+
+ return 0;
+}
+
+
+/* This is just a slightly neater wrapper round efx_i2c_fast_write
+ * in the case where the target doesn't take an offset
+ */
+int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
+ u8 device_id, const u8 *data, unsigned int len)
+{
+ return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
+}
+
+/* I2C receiving of bytes - does not send an offset byte */
+int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ u8 *bytes, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device */
+ i2c_start(i2c);
+
+ /* Read data from device */
+ rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
+ if (rc)
+ goto out;
+
+ for (i = 0; i < (len - 1); i++)
+ /* Read and acknowledge all but the last byte */
+ bytes[i] = i2c_recv_byte(i2c, 1);
+ /* Read last byte with no acknowledgement */
+ bytes[i] = i2c_recv_byte(i2c, 0);
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* SMBus and some I2C devices will time out if the I2C clock is
+ * held low for too long. This is most likely to happen in virtualised
+ * systems (when the entire domain is descheduled) but could in
+ * principle happen due to preemption on any busy system (and given the
+ * potential length of an I2C operation turning preemption off is not
+ * a sensible option). The following functions deal with the failure by
+ * retrying up to a fixed number of times.
+ */
+
+#define I2C_MAX_RETRIES (10)
+
+/* The timeout problem will result in -EIO. If the wrapped function
+ * returns any other error, pass this up and do not retry. */
+#define RETRY_WRAPPER(_f) \
+ int retries = I2C_MAX_RETRIES; \
+ int rc; \
+ while (retries) { \
+ rc = _f; \
+ if (rc != -EIO) \
+ return rc; \
+ retries--; \
+ } \
+ return rc; \
+
+int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
+{
+ RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
+}
+
+int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
+}
+
+int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, const u8 *data, unsigned int len)
+{
+ RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
+}
diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h
new file mode 100644
index 00000000000..291e561071f
--- /dev/null
+++ b/drivers/net/sfc/i2c-direct.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_I2C_DIRECT_H
+#define EFX_I2C_DIRECT_H
+
+#include "net_driver.h"
+
+/*
+ * Direct control of an I2C bus
+ */
+
+struct efx_i2c_interface;
+
+/**
+ * struct efx_i2c_bit_operations - I2C bus direct control methods
+ *
+ * I2C bus direct control methods.
+ *
+ * @setsda: Set state of SDA line
+ * @setscl: Set state of SCL line
+ * @getsda: Get state of SDA line
+ * @getscl: Get state of SCL line
+ * @udelay: Delay between each bit operation
+ * @mdelay: Delay between each byte write
+ */
+struct efx_i2c_bit_operations {
+ void (*setsda) (struct efx_i2c_interface *i2c);
+ void (*setscl) (struct efx_i2c_interface *i2c);
+ int (*getsda) (struct efx_i2c_interface *i2c);
+ int (*getscl) (struct efx_i2c_interface *i2c);
+ unsigned int udelay;
+ unsigned int mdelay;
+};
+
+/**
+ * struct efx_i2c_interface - an I2C interface
+ *
+ * An I2C interface.
+ *
+ * @efx: Attached Efx NIC
+ * @op: I2C bus control methods
+ * @sda: Current output state of SDA line
+ * @scl: Current output state of SCL line
+ */
+struct efx_i2c_interface {
+ struct efx_nic *efx;
+ struct efx_i2c_bit_operations *op;
+ unsigned int sda:1;
+ unsigned int scl:1;
+};
+
+extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
+extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ u8 *data, unsigned int len);
+extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+extern int efx_i2c_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len);
+extern int efx_i2c_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+
+extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ const u8 *bytes, unsigned int len);
+
+extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ u8 *bytes, unsigned int len);
+
+
+/* Versions of the API that retry on failure. */
+extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
+ u8 device_id);
+
+extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len);
+
+extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+
+#endif /* EFX_I2C_DIRECT_H */
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
new file mode 100644
index 00000000000..edd07d4dee1
--- /dev/null
+++ b/drivers/net/sfc/mac.h
@@ -0,0 +1,33 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_MAC_H
+#define EFX_MAC_H
+
+#include "net_driver.h"
+
+extern void falcon_xmac_writel(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg);
+extern void falcon_xmac_readl(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg);
+extern int falcon_init_xmac(struct efx_nic *efx);
+extern void falcon_reconfigure_xmac(struct efx_nic *efx);
+extern void falcon_update_stats_xmac(struct efx_nic *efx);
+extern void falcon_fini_xmac(struct efx_nic *efx);
+extern int falcon_check_xmac(struct efx_nic *efx);
+extern void falcon_xmac_sim_phy_event(struct efx_nic *efx);
+extern int falcon_xmac_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+extern int falcon_xmac_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+extern int falcon_xmac_set_pause(struct efx_nic *efx,
+ enum efx_fc_type pause_params);
+
+#endif
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
new file mode 100644
index 00000000000..dc06bb0aa57
--- /dev/null
+++ b/drivers/net/sfc/mdio_10g.c
@@ -0,0 +1,282 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+/*
+ * Useful functions for working with MDIO clause 45 PHYs
+ */
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "mdio_10g.h"
+#include "boards.h"
+
+int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
+ int spins, int spintime)
+{
+ u32 ctrl;
+ int phy_id = port->mii.phy_id;
+
+ /* Catch callers passing values in the wrong units (or just silly) */
+ EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
+
+ mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
+ (1 << MDIO_MMDREG_CTRL1_RESET_LBN));
+ /* Wait for the reset bit to clear. */
+ do {
+ msleep(spintime);
+ ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
+ spins--;
+
+ } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
+
+ return spins ? spins : -ETIMEDOUT;
+}
+
+static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
+ int fault_fatal)
+{
+ int status;
+ int phy_id = efx->mii.phy_id;
+
+ /* Read MMD STATUS2 to check it is responding. */
+ status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
+ if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
+ ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
+ MDIO_MMDREG_STAT2_PRESENT_VAL) {
+ EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
+ return -EIO;
+ }
+
+ /* Read MMD STATUS 1 to check for fault. */
+ status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
+ if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
+ if (fault_fatal) {
+ EFX_ERR(efx, "PHY MMD %d reporting fatal"
+ " fault: status %x\n", mmd, status);
+ return -EIO;
+ } else {
+ EFX_LOG(efx, "PHY MMD %d reporting status"
+ " %x (expected)\n", mmd, status);
+ }
+ }
+ return 0;
+}
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TIME 1000 /* ms */
+#define MDIO45_RESET_ITERS 100
+
+int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask)
+{
+ const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
+ int tries = MDIO45_RESET_ITERS;
+ int rc = 0;
+ int in_reset;
+
+ while (tries) {
+ int mask = mmd_mask;
+ int mmd = 0;
+ int stat;
+ in_reset = 0;
+ while (mask) {
+ if (mask & 1) {
+ stat = mdio_clause45_read(efx,
+ efx->mii.phy_id,
+ mmd,
+ MDIO_MMDREG_CTRL1);
+ if (stat < 0) {
+ EFX_ERR(efx, "failed to read status of"
+ " MMD %d\n", mmd);
+ return -EIO;
+ }
+ if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+ in_reset |= (1 << mmd);
+ }
+ mask = mask >> 1;
+ mmd++;
+ }
+ if (!in_reset)
+ break;
+ tries--;
+ msleep(spintime);
+ }
+ if (in_reset != 0) {
+ EFX_ERR(efx, "not all MMDs came out of reset in time."
+ " MMDs still in reset: %x\n", in_reset);
+ rc = -ETIMEDOUT;
+ }
+ return rc;
+}
+
+int mdio_clause45_check_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask, unsigned int fatal_mask)
+{
+ int devices, mmd = 0;
+ int probe_mmd;
+
+ /* Historically we have probed the PHYXS to find out what devices are
+ * present,but that doesn't work so well if the PHYXS isn't expected
+ * to exist, if so just find the first item in the list supplied. */
+ probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
+ __ffs(mmd_mask);
+ devices = mdio_clause45_read(efx, efx->mii.phy_id,
+ probe_mmd, MDIO_MMDREG_DEVS0);
+
+ /* Check all the expected MMDs are present */
+ if (devices < 0) {
+ EFX_ERR(efx, "failed to read devices present\n");
+ return -EIO;
+ }
+ if ((devices & mmd_mask) != mmd_mask) {
+ EFX_ERR(efx, "required MMDs not present: got %x, "
+ "wanted %x\n", devices, mmd_mask);
+ return -ENODEV;
+ }
+ EFX_TRACE(efx, "Devices present: %x\n", devices);
+
+ /* Check all required MMDs are responding and happy. */
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ int fault_fatal = fatal_mask & 1;
+ if (mdio_clause45_check_mmd(efx, mmd, fault_fatal))
+ return -EIO;
+ }
+ mmd_mask = mmd_mask >> 1;
+ fatal_mask = fatal_mask >> 1;
+ mmd++;
+ }
+
+ return 0;
+}
+
+int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
+{
+ int phy_id = efx->mii.phy_id;
+ int status;
+ int ok = 1;
+ int mmd = 0;
+ int good;
+
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ /* Double reads because link state is latched, and a
+ * read moves the current state into the register */
+ status = mdio_clause45_read(efx, phy_id,
+ mmd, MDIO_MMDREG_STAT1);
+ status = mdio_clause45_read(efx, phy_id,
+ mmd, MDIO_MMDREG_STAT1);
+
+ good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+ ok = ok && good;
+ }
+ mmd_mask = (mmd_mask >> 1);
+ mmd++;
+ }
+ return ok;
+}
+
+/**
+ * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
+ * @efx: Efx NIC
+ * @ecmd: Buffer for settings
+ *
+ * On return the 'port', 'speed', 'supported' and 'advertising' fields of
+ * ecmd have been filled out based on the PMA type.
+ */
+void mdio_clause45_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd)
+{
+ int pma_type;
+
+ /* If no PMA is present we are presumably talking something XAUI-ish
+ * like CX4. Which we report as FIBRE (see below) */
+ if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ return;
+ }
+
+ pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
+ pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
+
+ switch (pma_type) {
+ /* We represent CX4 as fibre in the absence of anything
+ better. */
+ case MDIO_PMAPMD_CTRL2_10G_CX4:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ break;
+ /* 10G Base-T */
+ case MDIO_PMAPMD_CTRL2_10G_BT:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_10000baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_1G_BT:
+ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_1000baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_100_BT:
+ ecmd->speed = SPEED_100;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_100baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_10_BT:
+ ecmd->speed = SPEED_10;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
+ ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
+ break;
+ /* All the other defined modes are flavours of
+ * 10G optical */
+ default:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ break;
+ }
+}
+
+/**
+ * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
+ * @efx: Efx NIC
+ * @ecmd: New settings
+ *
+ * Currently this just enforces that we are _not_ changing the
+ * 'port', 'speed', 'supported' or 'advertising' settings as these
+ * cannot be changed on any currently supported PHY.
+ */
+int mdio_clause45_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd)
+{
+ struct ethtool_cmd tmpcmd;
+ mdio_clause45_get_settings(efx, &tmpcmd);
+ /* None of the current PHYs support more than one mode
+ * of operation (and only 10GBT ever will), so keep things
+ * simple for now */
+ if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
+ (ecmd->supported == tmpcmd.supported) &&
+ (ecmd->advertising == tmpcmd.advertising))
+ return 0;
+ return -EOPNOTSUPP;
+}
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
new file mode 100644
index 00000000000..2214b6d820a
--- /dev/null
+++ b/drivers/net/sfc/mdio_10g.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_MDIO_10G_H
+#define EFX_MDIO_10G_H
+
+/*
+ * Definitions needed for doing 10G MDIO as specified in clause 45
+ * MDIO, which do not appear in Linux yet. Also some helper functions.
+ */
+
+#include "efx.h"
+#include "boards.h"
+
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD (1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS (2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS (3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS (4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS (5)
+/* Transmission convergence */
+#define MDIO_MMD_TC (6)
+/* Auto negotiation */
+#define MDIO_MMD_AN (7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1 (0)
+#define MDIO_MMDREG_STAT1 (1)
+#define MDIO_MMDREG_IDHI (2)
+#define MDIO_MMDREG_IDLOW (3)
+#define MDIO_MMDREG_SPEED (4)
+#define MDIO_MMDREG_DEVS0 (5)
+#define MDIO_MMDREG_DEVS1 (6)
+#define MDIO_MMDREG_CTRL2 (7)
+#define MDIO_MMDREG_STAT2 (8)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN (2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
+
+/* Bits in ID reg */
+#define MDIO_ID_REV(_id32) (_id32 & 0xf)
+#define MDIO_ID_MODEL(_id32) ((_id32 >> 4) & 0x3f)
+#define MDIO_ID_OUI(_id32) (_id32 >> 10)
+
+/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
+ * so the 'bit present' bit number of an MMD is the number of
+ * that MMD */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* PMA type (4 bits) */
+#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0)
+#define MDIO_PMAPMD_CTRL2_10G_EW (0x1)
+#define MDIO_PMAPMD_CTRL2_10G_LW (0x2)
+#define MDIO_PMAPMD_CTRL2_10G_SW (0x3)
+#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4)
+#define MDIO_PMAPMD_CTRL2_10G_ER (0x5)
+#define MDIO_PMAPMD_CTRL2_10G_LR (0x6)
+#define MDIO_PMAPMD_CTRL2_10G_SR (0x7)
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_10G_BT (0x9)
+/* Reserved */
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_1G_BT (0xc)
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_100_BT (0xe)
+#define MDIO_PMAPMD_CTRL2_10_BT (0xf)
+#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf)
+
+/* /\* PHY XGXS lane state *\/ */
+#define MDIO_PHYXS_LANE_STATE (0x18)
+#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
+
+/* AN registers */
+#define MDIO_AN_STATUS (1)
+#define MDIO_AN_STATUS_XNP_LBN (7)
+#define MDIO_AN_STATUS_PAGE_LBN (6)
+#define MDIO_AN_STATUS_AN_DONE_LBN (5)
+#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0)
+
+#define MDIO_AN_10GBT_STATUS (33)
+#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
+#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */
+#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
+#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
+#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
+#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
+#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */
+
+
+/* Packing of the prt and dev arguments of clause 45 style MDIO into a
+ * single int so they can be passed into the mdio_read/write functions
+ * that currently exist. Note that as Falcon is the only current user,
+ * the packed form is chosen to match what Falcon needs to write into
+ * a register. This is checked at compile-time so do not change it. If
+ * your target chip needs things layed out differently you will need
+ * to unpack the arguments in your chip-specific mdio functions.
+ */
+ /* These are defined by the standard. */
+#define MDIO45_PRT_ID_WIDTH (5)
+#define MDIO45_DEV_ID_WIDTH (5)
+
+/* The prt ID is just packed in immediately to the left of the dev ID */
+#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
+
+#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
+/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
+#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1)
+#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
+#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1))
+
+
+#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH
+#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH
+#define MDIO45_DEV_ID_COMP_LBN 0
+#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH
+
+/* Compose port and device into a phy_id */
+static inline int mdio_clause45_pack(u8 prt, u8 dev)
+{
+ efx_dword_t phy_id;
+ EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
+ MDIO45_DEV_ID_COMP, dev);
+ return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
+}
+
+static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
+{
+ efx_dword_t phy_id;
+ EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
+ *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
+ *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
+}
+
+static inline int mdio_clause45_read(struct efx_nic *efx,
+ u8 prt, u8 dev, u16 addr)
+{
+ return efx->mii.mdio_read(efx->net_dev,
+ mdio_clause45_pack(prt, dev), addr);
+}
+
+static inline void mdio_clause45_write(struct efx_nic *efx,
+ u8 prt, u8 dev, u16 addr, int value)
+{
+ efx->mii.mdio_write(efx->net_dev,
+ mdio_clause45_pack(prt, dev), addr, value);
+}
+
+
+static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
+{
+ int phy_id = efx->mii.phy_id;
+ u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
+ u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
+ return (id_hi << 16) | (id_low);
+}
+
+static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
+{
+ int i, sync, lane_status;
+
+ for (i = 0; i < 2; ++i)
+ lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PHYXS,
+ MDIO_PHYXS_LANE_STATE);
+
+ sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
+ if (!sync)
+ EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
+ return sync;
+}
+
+extern const char *mdio_clause45_mmd_name(int mmd);
+
+/*
+ * Reset a specific MMD and wait for reset to clear.
+ * Return number of spins left (>0) on success, -%ETIMEDOUT on failure.
+ *
+ * This function will sleep
+ */
+extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
+ int spins, int spintime);
+
+/* As mdio_clause45_check_mmd but for multiple MMDs */
+int mdio_clause45_check_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask, unsigned int fatal_mask);
+
+/* Check the link status of specified mmds in bit mask */
+extern int mdio_clause45_links_ok(struct efx_nic *efx,
+ unsigned int mmd_mask);
+
+/* Read (some of) the PHY settings over MDIO */
+extern void mdio_clause45_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+
+/* Set (some of) the PHY settings over MDIO */
+extern int mdio_clause45_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+
+/* Wait for specified MMDs to exit reset within a timeout */
+extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask);
+
+#endif /* EFX_MDIO_10G_H */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
new file mode 100644
index 00000000000..c505482c252
--- /dev/null
+++ b/drivers/net/sfc/net_driver.h
@@ -0,0 +1,883 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+/* Common definitions for all Efx net driver code */
+
+#ifndef EFX_NET_DRIVER_H
+#define EFX_NET_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/timer.h>
+#include <linux/mii.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/workqueue.h>
+#include <linux/inet_lro.h>
+
+#include "enum.h"
+#include "bitfield.h"
+#include "i2c-direct.h"
+
+#define EFX_MAX_LRO_DESCRIPTORS 8
+#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
+
+/**************************************************************************
+ *
+ * Build definitions
+ *
+ **************************************************************************/
+#ifndef EFX_DRIVER_NAME
+#define EFX_DRIVER_NAME "sfc"
+#endif
+#define EFX_DRIVER_VERSION "2.2.0136"
+
+#ifdef EFX_ENABLE_DEBUG
+#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
+#define EFX_WARN_ON_PARANOID(x) WARN_ON(x)
+#else
+#define EFX_BUG_ON_PARANOID(x) do {} while (0)
+#define EFX_WARN_ON_PARANOID(x) do {} while (0)
+#endif
+
+#define NET_DEV_REGISTERED(efx) \
+ ((efx)->net_dev->reg_state == NETREG_REGISTERED)
+
+/* Include net device name in log messages if it has been registered.
+ * Use efx->name not efx->net_dev->name so that races with (un)registration
+ * are harmless.
+ */
+#define NET_DEV_NAME(efx) (NET_DEV_REGISTERED(efx) ? (efx)->name : "")
+
+/* Un-rate-limited logging */
+#define EFX_ERR(efx, fmt, args...) \
+dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
+
+#define EFX_INFO(efx, fmt, args...) \
+dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
+
+#ifdef EFX_ENABLE_DEBUG
+#define EFX_LOG(efx, fmt, args...) \
+dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+#else
+#define EFX_LOG(efx, fmt, args...) \
+dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+#endif
+
+#define EFX_TRACE(efx, fmt, args...) do {} while (0)
+
+#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
+
+/* Rate-limited logging */
+#define EFX_ERR_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
+
+#define EFX_INFO_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
+
+#define EFX_LOG_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
+
+/* Kernel headers may redefine inline anyway */
+#ifndef inline
+#define inline inline __attribute__ ((always_inline))
+#endif
+
+/**************************************************************************
+ *
+ * Efx data structures
+ *
+ **************************************************************************/
+
+#define EFX_MAX_CHANNELS 32
+#define EFX_MAX_TX_QUEUES 1
+#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
+
+/**
+ * struct efx_special_buffer - An Efx special buffer
+ * @addr: CPU base address of the buffer
+ * @dma_addr: DMA base address of the buffer
+ * @len: Buffer length, in bytes
+ * @index: Buffer index within controller;s buffer table
+ * @entries: Number of buffer table entries
+ *
+ * Special buffers are used for the event queues and the TX and RX
+ * descriptor queues for each channel. They are *not* used for the
+ * actual transmit and receive buffers.
+ *
+ * Note that for Falcon, TX and RX descriptor queues live in host memory.
+ * Allocation and freeing procedures must take this into account.
+ */
+struct efx_special_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ unsigned int len;
+ int index;
+ int entries;
+};
+
+/**
+ * struct efx_tx_buffer - An Efx TX buffer
+ * @skb: The associated socket buffer.
+ * Set only on the final fragment of a packet; %NULL for all other
+ * fragments. When this fragment completes, then we can free this
+ * skb.
+ * @dma_addr: DMA address of the fragment.
+ * @len: Length of this fragment.
+ * This field is zero when the queue slot is empty.
+ * @continuation: True if this fragment is not the end of a packet.
+ * @unmap_single: True if pci_unmap_single should be used.
+ * @unmap_addr: DMA address to unmap
+ * @unmap_len: Length of this fragment to unmap
+ */
+struct efx_tx_buffer {
+ const struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ unsigned short len;
+ unsigned char continuation;
+ unsigned char unmap_single;
+ dma_addr_t unmap_addr;
+ unsigned short unmap_len;
+};
+
+/**
+ * struct efx_tx_queue - An Efx TX queue
+ *
+ * This is a ring buffer of TX fragments.
+ * Since the TX completion path always executes on the same
+ * CPU and the xmit path can operate on different CPUs,
+ * performance is increased by ensuring that the completion
+ * path and the xmit path operate on different cache lines.
+ * This is particularly important if the xmit path is always
+ * executing on one CPU which is different from the completion
+ * path. There is also a cache line for members which are
+ * read but not written on the fast path.
+ *
+ * @efx: The associated Efx NIC
+ * @queue: DMA queue number
+ * @used: Queue is used by net driver
+ * @channel: The associated channel
+ * @buffer: The software buffer ring
+ * @txd: The hardware descriptor ring
+ * @read_count: Current read pointer.
+ * This is the number of buffers that have been removed from both rings.
+ * @stopped: Stopped flag.
+ * Set if this TX queue is currently stopping its port.
+ * @insert_count: Current insert pointer
+ * This is the number of buffers that have been added to the
+ * software ring.
+ * @write_count: Current write pointer
+ * This is the number of buffers that have been added to the
+ * hardware ring.
+ * @old_read_count: The value of read_count when last checked.
+ * This is here for performance reasons. The xmit path will
+ * only get the up-to-date value of read_count if this
+ * variable indicates that the queue is full. This is to
+ * avoid cache-line ping-pong between the xmit path and the
+ * completion path.
+ */
+struct efx_tx_queue {
+ /* Members which don't change on the fast path */
+ struct efx_nic *efx ____cacheline_aligned_in_smp;
+ int queue;
+ int used;
+ struct efx_channel *channel;
+ struct efx_nic *nic;
+ struct efx_tx_buffer *buffer;
+ struct efx_special_buffer txd;
+
+ /* Members used mainly on the completion path */
+ unsigned int read_count ____cacheline_aligned_in_smp;
+ int stopped;
+
+ /* Members used only on the xmit path */
+ unsigned int insert_count ____cacheline_aligned_in_smp;
+ unsigned int write_count;
+ unsigned int old_read_count;
+};
+
+/**
+ * struct efx_rx_buffer - An Efx RX data buffer
+ * @dma_addr: DMA base address of the buffer
+ * @skb: The associated socket buffer, if any.
+ * If both this and page are %NULL, the buffer slot is currently free.
+ * @page: The associated page buffer, if any.
+ * If both this and skb are %NULL, the buffer slot is currently free.
+ * @data: Pointer to ethernet header
+ * @len: Buffer length, in bytes.
+ * @unmap_addr: DMA address to unmap
+ */
+struct efx_rx_buffer {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+ struct page *page;
+ char *data;
+ unsigned int len;
+ dma_addr_t unmap_addr;
+};
+
+/**
+ * struct efx_rx_queue - An Efx RX queue
+ * @efx: The associated Efx NIC
+ * @queue: DMA queue number
+ * @used: Queue is used by net driver
+ * @channel: The associated channel
+ * @buffer: The software buffer ring
+ * @rxd: The hardware descriptor ring
+ * @added_count: Number of buffers added to the receive queue.
+ * @notified_count: Number of buffers given to NIC (<= @added_count).
+ * @removed_count: Number of buffers removed from the receive queue.
+ * @add_lock: Receive queue descriptor add spin lock.
+ * This lock must be held in order to add buffers to the RX
+ * descriptor ring (rxd and buffer) and to update added_count (but
+ * not removed_count).
+ * @max_fill: RX descriptor maximum fill level (<= ring size)
+ * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
+ * (<= @max_fill)
+ * @fast_fill_limit: The level to which a fast fill will fill
+ * (@fast_fill_trigger <= @fast_fill_limit <= @max_fill)
+ * @min_fill: RX descriptor minimum non-zero fill level.
+ * This records the minimum fill level observed when a ring
+ * refill was triggered.
+ * @min_overfill: RX descriptor minimum overflow fill level.
+ * This records the minimum fill level at which RX queue
+ * overflow was observed. It should never be set.
+ * @alloc_page_count: RX allocation strategy counter.
+ * @alloc_skb_count: RX allocation strategy counter.
+ * @work: Descriptor push work thread
+ * @buf_page: Page for next RX buffer.
+ * We can use a single page for multiple RX buffers. This tracks
+ * the remaining space in the allocation.
+ * @buf_dma_addr: Page's DMA address.
+ * @buf_data: Page's host address.
+ */
+struct efx_rx_queue {
+ struct efx_nic *efx;
+ int queue;
+ int used;
+ struct efx_channel *channel;
+ struct efx_rx_buffer *buffer;
+ struct efx_special_buffer rxd;
+
+ int added_count;
+ int notified_count;
+ int removed_count;
+ spinlock_t add_lock;
+ unsigned int max_fill;
+ unsigned int fast_fill_trigger;
+ unsigned int fast_fill_limit;
+ unsigned int min_fill;
+ unsigned int min_overfill;
+ unsigned int alloc_page_count;
+ unsigned int alloc_skb_count;
+ struct delayed_work work;
+ unsigned int slow_fill_count;
+
+ struct page *buf_page;
+ dma_addr_t buf_dma_addr;
+ char *buf_data;
+};
+
+/**
+ * struct efx_buffer - An Efx general-purpose buffer
+ * @addr: host base address of the buffer
+ * @dma_addr: DMA base address of the buffer
+ * @len: Buffer length, in bytes
+ *
+ * Falcon uses these buffers for its interrupt status registers and
+ * MAC stats dumps.
+ */
+struct efx_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ unsigned int len;
+};
+
+
+/* Flags for channel->used_flags */
+#define EFX_USED_BY_RX 1
+#define EFX_USED_BY_TX 2
+#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX)
+
+enum efx_rx_alloc_method {
+ RX_ALLOC_METHOD_AUTO = 0,
+ RX_ALLOC_METHOD_SKB = 1,
+ RX_ALLOC_METHOD_PAGE = 2,
+};
+
+/**
+ * struct efx_channel - An Efx channel
+ *
+ * A channel comprises an event queue, at least one TX queue, at least
+ * one RX queue, and an associated tasklet for processing the event
+ * queue.
+ *
+ * @efx: Associated Efx NIC
+ * @evqnum: Event queue number
+ * @channel: Channel instance number
+ * @used_flags: Channel is used by net driver
+ * @enabled: Channel enabled indicator
+ * @irq: IRQ number (MSI and MSI-X only)
+ * @has_interrupt: Channel has an interrupt
+ * @irq_moderation: IRQ moderation value (in us)
+ * @napi_dev: Net device used with NAPI
+ * @napi_str: NAPI control structure
+ * @reset_work: Scheduled reset work thread
+ * @work_pending: Is work pending via NAPI?
+ * @eventq: Event queue buffer
+ * @eventq_read_ptr: Event queue read pointer
+ * @last_eventq_read_ptr: Last event queue read pointer value.
+ * @eventq_magic: Event queue magic value for driver-generated test events
+ * @lro_mgr: LRO state
+ * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
+ * and diagnostic counters
+ * @rx_alloc_push_pages: RX allocation method currently in use for pushing
+ * descriptors
+ * @rx_alloc_pop_pages: RX allocation method currently in use for popping
+ * descriptors
+ * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
+ * @n_rx_ip_frag_err: Count of RX IP fragment errors
+ * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
+ * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
+ * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
+ * @n_rx_overlength: Count of RX_OVERLENGTH errors
+ * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
+ */
+struct efx_channel {
+ struct efx_nic *efx;
+ int evqnum;
+ int channel;
+ int used_flags;
+ int enabled;
+ int irq;
+ unsigned int has_interrupt;
+ unsigned int irq_moderation;
+ struct net_device *napi_dev;
+ struct napi_struct napi_str;
+ struct work_struct reset_work;
+ int work_pending;
+ struct efx_special_buffer eventq;
+ unsigned int eventq_read_ptr;
+ unsigned int last_eventq_read_ptr;
+ unsigned int eventq_magic;
+
+ struct net_lro_mgr lro_mgr;
+ int rx_alloc_level;
+ int rx_alloc_push_pages;
+ int rx_alloc_pop_pages;
+
+ unsigned n_rx_tobe_disc;
+ unsigned n_rx_ip_frag_err;
+ unsigned n_rx_ip_hdr_chksum_err;
+ unsigned n_rx_tcp_udp_chksum_err;
+ unsigned n_rx_frm_trunc;
+ unsigned n_rx_overlength;
+ unsigned n_skbuff_leaks;
+
+ /* Used to pipeline received packets in order to optimise memory
+ * access with prefetches.
+ */
+ struct efx_rx_buffer *rx_pkt;
+ int rx_pkt_csummed;
+
+};
+
+/**
+ * struct efx_blinker - S/W LED blinking context
+ * @led_num: LED ID (board-specific meaning)
+ * @state: Current state - on or off
+ * @resubmit: Timer resubmission flag
+ * @timer: Control timer for blinking
+ */
+struct efx_blinker {
+ int led_num;
+ int state;
+ int resubmit;
+ struct timer_list timer;
+};
+
+
+/**
+ * struct efx_board - board information
+ * @type: Board model type
+ * @major: Major rev. ('A', 'B' ...)
+ * @minor: Minor rev. (0, 1, ...)
+ * @init: Initialisation function
+ * @init_leds: Sets up board LEDs
+ * @set_fault_led: Turns the fault LED on or off
+ * @blink: Starts/stops blinking
+ * @blinker: used to blink LEDs in software
+ */
+struct efx_board {
+ int type;
+ int major;
+ int minor;
+ int (*init) (struct efx_nic *nic);
+ /* As the LEDs are typically attached to the PHY, LEDs
+ * have a separate init callback that happens later than
+ * board init. */
+ int (*init_leds)(struct efx_nic *efx);
+ void (*set_fault_led) (struct efx_nic *efx, int state);
+ void (*blink) (struct efx_nic *efx, int start);
+ struct efx_blinker blinker;
+};
+
+enum efx_int_mode {
+ /* Be careful if altering to correct macro below */
+ EFX_INT_MODE_MSIX = 0,
+ EFX_INT_MODE_MSI = 1,
+ EFX_INT_MODE_LEGACY = 2,
+ EFX_INT_MODE_MAX /* Insert any new items before this */
+};
+#define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
+
+enum phy_type {
+ PHY_TYPE_NONE = 0,
+ PHY_TYPE_CX4_RTMR = 1,
+ PHY_TYPE_1G_ALASKA = 2,
+ PHY_TYPE_10XPRESS = 3,
+ PHY_TYPE_XFP = 4,
+ PHY_TYPE_PM8358 = 6,
+ PHY_TYPE_MAX /* Insert any new items before this */
+};
+
+#define PHY_ADDR_INVALID 0xff
+
+enum nic_state {
+ STATE_INIT = 0,
+ STATE_RUNNING = 1,
+ STATE_FINI = 2,
+ STATE_RESETTING = 3, /* rtnl_lock always held */
+ STATE_DISABLED = 4,
+ STATE_MAX,
+};
+
+/*
+ * Alignment of page-allocated RX buffers
+ *
+ * Controls the number of bytes inserted at the start of an RX buffer.
+ * This is the equivalent of NET_IP_ALIGN [which controls the alignment
+ * of the skb->head for hardware DMA].
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define EFX_PAGE_IP_ALIGN 0
+#else
+#define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
+#endif
+
+/*
+ * Alignment of the skb->head which wraps a page-allocated RX buffer
+ *
+ * The skb allocated to wrap an rx_buffer can have this alignment. Since
+ * the data is memcpy'd from the rx_buf, it does not need to be equal to
+ * EFX_PAGE_IP_ALIGN.
+ */
+#define EFX_PAGE_SKB_ALIGN 2
+
+/* Forward declaration */
+struct efx_nic;
+
+/* Pseudo bit-mask flow control field */
+enum efx_fc_type {
+ EFX_FC_RX = 1,
+ EFX_FC_TX = 2,
+ EFX_FC_AUTO = 4,
+};
+
+/**
+ * struct efx_phy_operations - Efx PHY operations table
+ * @init: Initialise PHY
+ * @fini: Shut down PHY
+ * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
+ * @clear_interrupt: Clear down interrupt
+ * @blink: Blink LEDs
+ * @check_hw: Check hardware
+ * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
+ * @mmds: MMD presence mask
+ */
+struct efx_phy_operations {
+ int (*init) (struct efx_nic *efx);
+ void (*fini) (struct efx_nic *efx);
+ void (*reconfigure) (struct efx_nic *efx);
+ void (*clear_interrupt) (struct efx_nic *efx);
+ int (*check_hw) (struct efx_nic *efx);
+ void (*reset_xaui) (struct efx_nic *efx);
+ int mmds;
+};
+
+/*
+ * Efx extended statistics
+ *
+ * Not all statistics are provided by all supported MACs. The purpose
+ * is this structure is to contain the raw statistics provided by each
+ * MAC.
+ */
+struct efx_mac_stats {
+ u64 tx_bytes;
+ u64 tx_good_bytes;
+ u64 tx_bad_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bad;
+ unsigned long tx_pause;
+ unsigned long tx_control;
+ unsigned long tx_unicast;
+ unsigned long tx_multicast;
+ unsigned long tx_broadcast;
+ unsigned long tx_lt64;
+ unsigned long tx_64;
+ unsigned long tx_65_to_127;
+ unsigned long tx_128_to_255;
+ unsigned long tx_256_to_511;
+ unsigned long tx_512_to_1023;
+ unsigned long tx_1024_to_15xx;
+ unsigned long tx_15xx_to_jumbo;
+ unsigned long tx_gtjumbo;
+ unsigned long tx_collision;
+ unsigned long tx_single_collision;
+ unsigned long tx_multiple_collision;
+ unsigned long tx_excessive_collision;
+ unsigned long tx_deferred;
+ unsigned long tx_late_collision;
+ unsigned long tx_excessive_deferred;
+ unsigned long tx_non_tcpudp;
+ unsigned long tx_mac_src_error;
+ unsigned long tx_ip_src_error;
+ u64 rx_bytes;
+ u64 rx_good_bytes;
+ u64 rx_bad_bytes;
+ unsigned long rx_packets;
+ unsigned long rx_good;
+ unsigned long rx_bad;
+ unsigned long rx_pause;
+ unsigned long rx_control;
+ unsigned long rx_unicast;
+ unsigned long rx_multicast;
+ unsigned long rx_broadcast;
+ unsigned long rx_lt64;
+ unsigned long rx_64;
+ unsigned long rx_65_to_127;
+ unsigned long rx_128_to_255;
+ unsigned long rx_256_to_511;
+ unsigned long rx_512_to_1023;
+ unsigned long rx_1024_to_15xx;
+ unsigned long rx_15xx_to_jumbo;
+ unsigned long rx_gtjumbo;
+ unsigned long rx_bad_lt64;
+ unsigned long rx_bad_64_to_15xx;
+ unsigned long rx_bad_15xx_to_jumbo;
+ unsigned long rx_bad_gtjumbo;
+ unsigned long rx_overflow;
+ unsigned long rx_missed;
+ unsigned long rx_false_carrier;
+ unsigned long rx_symbol_error;
+ unsigned long rx_align_error;
+ unsigned long rx_length_error;
+ unsigned long rx_internal_error;
+ unsigned long rx_good_lt64;
+};
+
+/* Number of bits used in a multicast filter hash address */
+#define EFX_MCAST_HASH_BITS 8
+
+/* Number of (single-bit) entries in a multicast filter hash */
+#define EFX_MCAST_HASH_ENTRIES (1 << EFX_MCAST_HASH_BITS)
+
+/* An Efx multicast filter hash */
+union efx_multicast_hash {
+ u8 byte[EFX_MCAST_HASH_ENTRIES / 8];
+ efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
+};
+
+/**
+ * struct efx_nic - an Efx NIC
+ * @name: Device name (net device name or bus id before net device registered)
+ * @pci_dev: The PCI device
+ * @type: Controller type attributes
+ * @legacy_irq: IRQ number
+ * @workqueue: Workqueue for resets, port reconfigures and the HW monitor
+ * @reset_work: Scheduled reset workitem
+ * @monitor_work: Hardware monitor workitem
+ * @membase_phys: Memory BAR value as physical address
+ * @membase: Memory BAR value
+ * @biu_lock: BIU (bus interface unit) lock
+ * @interrupt_mode: Interrupt mode
+ * @i2c: I2C interface
+ * @board_info: Board-level information
+ * @state: Device state flag. Serialised by the rtnl_lock.
+ * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
+ * @tx_queue: TX DMA queues
+ * @rx_queue: RX DMA queues
+ * @channel: Channels
+ * @rss_queues: Number of RSS queues
+ * @rx_buffer_len: RX buffer length
+ * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @irq_status: Interrupt status buffer
+ * @last_irq_cpu: Last CPU to handle interrupt.
+ * This register is written with the SMP processor ID whenever an
+ * interrupt is handled. It is used by falcon_test_interrupt()
+ * to verify that an interrupt has occurred.
+ * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
+ * @nic_data: Hardware dependant state
+ * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
+ * efx_reconfigure_port()
+ * @port_enabled: Port enabled indicator.
+ * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
+ * efx_reconfigure_work with kernel interfaces. Safe to read under any
+ * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
+ * be held to modify it.
+ * @port_initialized: Port initialized?
+ * @net_dev: Operating system network device. Consider holding the rtnl lock
+ * @rx_checksum_enabled: RX checksumming enabled
+ * @netif_stop_count: Port stop count
+ * @netif_stop_lock: Port stop lock
+ * @mac_stats: MAC statistics. These include all statistics the MACs
+ * can provide. Generic code converts these into a standard
+ * &struct net_device_stats.
+ * @stats_buffer: DMA buffer for statistics
+ * @stats_lock: Statistics update lock
+ * @mac_address: Permanent MAC address
+ * @phy_type: PHY type
+ * @phy_lock: PHY access lock
+ * @phy_op: PHY interface
+ * @phy_data: PHY private data (including PHY-specific stats)
+ * @mii: PHY interface
+ * @phy_powered: PHY power state
+ * @tx_disabled: PHY transmitter turned off
+ * @link_up: Link status
+ * @link_options: Link options (MII/GMII format)
+ * @n_link_state_changes: Number of times the link has changed state
+ * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
+ * @multicast_hash: Multicast hash table
+ * @flow_control: Flow control flags - separate RX/TX so can't use link_options
+ * @reconfigure_work: work item for dealing with PHY events
+ *
+ * The @priv field of the corresponding &struct net_device points to
+ * this.
+ */
+struct efx_nic {
+ char name[IFNAMSIZ];
+ struct pci_dev *pci_dev;
+ const struct efx_nic_type *type;
+ int legacy_irq;
+ struct workqueue_struct *workqueue;
+ struct work_struct reset_work;
+ struct delayed_work monitor_work;
+ unsigned long membase_phys;
+ void __iomem *membase;
+ spinlock_t biu_lock;
+ enum efx_int_mode interrupt_mode;
+
+ struct efx_i2c_interface i2c;
+ struct efx_board board_info;
+
+ enum nic_state state;
+ enum reset_type reset_pending;
+
+ struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
+ struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
+ struct efx_channel channel[EFX_MAX_CHANNELS];
+
+ int rss_queues;
+ unsigned int rx_buffer_len;
+ unsigned int rx_buffer_order;
+
+ struct efx_buffer irq_status;
+ volatile signed int last_irq_cpu;
+
+ unsigned n_rx_nodesc_drop_cnt;
+
+ void *nic_data;
+
+ struct mutex mac_lock;
+ int port_enabled;
+
+ int port_initialized;
+ struct net_device *net_dev;
+ int rx_checksum_enabled;
+
+ atomic_t netif_stop_count;
+ spinlock_t netif_stop_lock;
+
+ struct efx_mac_stats mac_stats;
+ struct efx_buffer stats_buffer;
+ spinlock_t stats_lock;
+
+ unsigned char mac_address[ETH_ALEN];
+
+ enum phy_type phy_type;
+ spinlock_t phy_lock;
+ struct efx_phy_operations *phy_op;
+ void *phy_data;
+ struct mii_if_info mii;
+
+ int link_up;
+ unsigned int link_options;
+ unsigned int n_link_state_changes;
+
+ int promiscuous;
+ union efx_multicast_hash multicast_hash;
+ enum efx_fc_type flow_control;
+ struct work_struct reconfigure_work;
+
+ atomic_t rx_reset;
+};
+
+/**
+ * struct efx_nic_type - Efx device type definition
+ * @mem_bar: Memory BAR number
+ * @mem_map_size: Memory BAR mapped size
+ * @txd_ptr_tbl_base: TX descriptor ring base address
+ * @rxd_ptr_tbl_base: RX descriptor ring base address
+ * @buf_tbl_base: Buffer table base address
+ * @evq_ptr_tbl_base: Event queue pointer table base address
+ * @evq_rptr_tbl_base: Event queue read-pointer table base address
+ * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
+ * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
+ * @evq_size: Event queue size (must be a power of two)
+ * @max_dma_mask: Maximum possible DMA mask
+ * @tx_dma_mask: TX DMA mask
+ * @bug5391_mask: Address mask for bug 5391 workaround
+ * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
+ * @rx_xon_thresh: RX FIFO XON watermark (bytes)
+ * @rx_buffer_padding: Padding added to each RX buffer
+ * @max_interrupt_mode: Highest capability interrupt mode supported
+ * from &enum efx_init_mode.
+ * @phys_addr_channels: Number of channels with physically addressed
+ * descriptors
+ */
+struct efx_nic_type {
+ unsigned int mem_bar;
+ unsigned int mem_map_size;
+ unsigned int txd_ptr_tbl_base;
+ unsigned int rxd_ptr_tbl_base;
+ unsigned int buf_tbl_base;
+ unsigned int evq_ptr_tbl_base;
+ unsigned int evq_rptr_tbl_base;
+
+ unsigned int txd_ring_mask;
+ unsigned int rxd_ring_mask;
+ unsigned int evq_size;
+ dma_addr_t max_dma_mask;
+ unsigned int tx_dma_mask;
+ unsigned bug5391_mask;
+
+ int rx_xoff_thresh;
+ int rx_xon_thresh;
+ unsigned int rx_buffer_padding;
+ unsigned int max_interrupt_mode;
+ unsigned int phys_addr_channels;
+};
+
+/**************************************************************************
+ *
+ * Prototypes and inline functions
+ *
+ *************************************************************************/
+
+/* Iterate over all used channels */
+#define efx_for_each_channel(_channel, _efx) \
+ for (_channel = &_efx->channel[0]; \
+ _channel < &_efx->channel[EFX_MAX_CHANNELS]; \
+ _channel++) \
+ if (!_channel->used_flags) \
+ continue; \
+ else
+
+/* Iterate over all used channels with interrupts */
+#define efx_for_each_channel_with_interrupt(_channel, _efx) \
+ for (_channel = &_efx->channel[0]; \
+ _channel < &_efx->channel[EFX_MAX_CHANNELS]; \
+ _channel++) \
+ if (!(_channel->used_flags && _channel->has_interrupt)) \
+ continue; \
+ else
+
+/* Iterate over all used TX queues */
+#define efx_for_each_tx_queue(_tx_queue, _efx) \
+ for (_tx_queue = &_efx->tx_queue[0]; \
+ _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue++) \
+ if (!_tx_queue->used) \
+ continue; \
+ else
+
+/* Iterate over all TX queues belonging to a channel */
+#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
+ for (_tx_queue = &_channel->efx->tx_queue[0]; \
+ _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue++) \
+ if ((!_tx_queue->used) || \
+ (_tx_queue->channel != _channel)) \
+ continue; \
+ else
+
+/* Iterate over all used RX queues */
+#define efx_for_each_rx_queue(_rx_queue, _efx) \
+ for (_rx_queue = &_efx->rx_queue[0]; \
+ _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES]; \
+ _rx_queue++) \
+ if (!_rx_queue->used) \
+ continue; \
+ else
+
+/* Iterate over all RX queues belonging to a channel */
+#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
+ for (_rx_queue = &_channel->efx->rx_queue[0]; \
+ _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES]; \
+ _rx_queue++) \
+ if ((!_rx_queue->used) || \
+ (_rx_queue->channel != _channel)) \
+ continue; \
+ else
+
+/* Returns a pointer to the specified receive buffer in the RX
+ * descriptor queue.
+ */
+static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
+ unsigned int index)
+{
+ return (&rx_queue->buffer[index]);
+}
+
+/* Set bit in a little-endian bitfield */
+static inline void set_bit_le(int nr, unsigned char *addr)
+{
+ addr[nr / 8] |= (1 << (nr % 8));
+}
+
+/* Clear bit in a little-endian bitfield */
+static inline void clear_bit_le(int nr, unsigned char *addr)
+{
+ addr[nr / 8] &= ~(1 << (nr % 8));
+}
+
+
+/**
+ * EFX_MAX_FRAME_LEN - calculate maximum frame length
+ *
+ * This calculates the maximum frame length that will be used for a
+ * given MTU. The frame length will be equal to the MTU plus a
+ * constant amount of header space and padding. This is the quantity
+ * that the net driver will program into the MAC as the maximum frame
+ * length.
+ *
+ * The 10G MAC used in Falcon requires 8-byte alignment on the frame
+ * length, so we round up to the nearest 8.
+ */
+#define EFX_MAX_FRAME_LEN(mtu) \
+ ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7)
+
+
+#endif /* EFX_NET_DRIVER_H */
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
new file mode 100644
index 00000000000..9d02c84e6b2
--- /dev/null
+++ b/drivers/net/sfc/phy.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_PHY_H
+#define EFX_PHY_H
+
+/****************************************************************************
+ * 10Xpress (SFX7101) PHY
+ */
+extern struct efx_phy_operations falcon_tenxpress_phy_ops;
+
+enum tenxpress_state {
+ TENXPRESS_STATUS_OFF = 0,
+ TENXPRESS_STATUS_OTEMP = 1,
+ TENXPRESS_STATUS_NORMAL = 2,
+};
+
+extern void tenxpress_set_state(struct efx_nic *efx,
+ enum tenxpress_state state);
+extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
+extern void tenxpress_crc_err(struct efx_nic *efx);
+
+/****************************************************************************
+ * Exported functions from the driver for XFP optical PHYs
+ */
+extern struct efx_phy_operations falcon_xfp_phy_ops;
+
+/* The QUAKE XFP PHY provides various H/W control states for LEDs */
+#define QUAKE_LED_LINK_INVAL (0)
+#define QUAKE_LED_LINK_STAT (1)
+#define QUAKE_LED_LINK_ACT (2)
+#define QUAKE_LED_LINK_ACTSTAT (3)
+#define QUAKE_LED_OFF (4)
+#define QUAKE_LED_ON (5)
+#define QUAKE_LED_LINK_INPUT (6) /* Pin is an input. */
+/* What link the LED tracks */
+#define QUAKE_LED_TXLINK (0)
+#define QUAKE_LED_RXLINK (8)
+
+extern void xfp_set_led(struct efx_nic *p, int led, int state);
+
+#endif
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
new file mode 100644
index 00000000000..551299b462a
--- /dev/null
+++ b/drivers/net/sfc/rx.c
@@ -0,0 +1,875 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include "net_driver.h"
+#include "rx.h"
+#include "efx.h"
+#include "falcon.h"
+#include "workarounds.h"
+
+/* Number of RX descriptors pushed at once. */
+#define EFX_RX_BATCH 8
+
+/* Size of buffer allocated for skb header area. */
+#define EFX_SKB_HEADERS 64u
+
+/*
+ * rx_alloc_method - RX buffer allocation method
+ *
+ * This driver supports two methods for allocating and using RX buffers:
+ * each RX buffer may be backed by an skb or by an order-n page.
+ *
+ * When LRO is in use then the second method has a lower overhead,
+ * since we don't have to allocate then free skbs on reassembled frames.
+ *
+ * Values:
+ * - RX_ALLOC_METHOD_AUTO = 0
+ * - RX_ALLOC_METHOD_SKB = 1
+ * - RX_ALLOC_METHOD_PAGE = 2
+ *
+ * The heuristic for %RX_ALLOC_METHOD_AUTO is a simple hysteresis count
+ * controlled by the parameters below.
+ *
+ * - Since pushing and popping descriptors are separated by the rx_queue
+ * size, so the watermarks should be ~rxd_size.
+ * - The performance win by using page-based allocation for LRO is less
+ * than the performance hit of using page-based allocation of non-LRO,
+ * so the watermarks should reflect this.
+ *
+ * Per channel we maintain a single variable, updated by each channel:
+ *
+ * rx_alloc_level += (lro_performed ? RX_ALLOC_FACTOR_LRO :
+ * RX_ALLOC_FACTOR_SKB)
+ * Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
+ * limits the hysteresis), and update the allocation strategy:
+ *
+ * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
+ * RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
+ */
+static int rx_alloc_method = RX_ALLOC_METHOD_PAGE;
+
+#define RX_ALLOC_LEVEL_LRO 0x2000
+#define RX_ALLOC_LEVEL_MAX 0x3000
+#define RX_ALLOC_FACTOR_LRO 1
+#define RX_ALLOC_FACTOR_SKB (-2)
+
+/* This is the percentage fill level below which new RX descriptors
+ * will be added to the RX descriptor ring.
+ */
+static unsigned int rx_refill_threshold = 90;
+
+/* This is the percentage fill level to which an RX queue will be refilled
+ * when the "RX refill threshold" is reached.
+ */
+static unsigned int rx_refill_limit = 95;
+
+/*
+ * RX maximum head room required.
+ *
+ * This must be at least 1 to prevent overflow and at least 2 to allow
+ * pipelined receives.
+ */
+#define EFX_RXD_HEAD_ROOM 2
+
+/* Macros for zero-order pages (potentially) containing multiple RX buffers */
+#define RX_DATA_OFFSET(_data) \
+ (((unsigned long) (_data)) & (PAGE_SIZE-1))
+#define RX_BUF_OFFSET(_rx_buf) \
+ RX_DATA_OFFSET((_rx_buf)->data)
+
+#define RX_PAGE_SIZE(_efx) \
+ (PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
+
+
+/**************************************************************************
+ *
+ * Linux generic LRO handling
+ *
+ **************************************************************************
+ */
+
+static int efx_lro_get_skb_hdr(struct sk_buff *skb, void **ip_hdr,
+ void **tcpudp_hdr, u64 *hdr_flags, void *priv)
+{
+ struct efx_channel *channel = (struct efx_channel *)priv;
+ struct iphdr *iph;
+ struct tcphdr *th;
+
+ iph = (struct iphdr *)skb->data;
+ if (skb->protocol != htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP)
+ goto fail;
+
+ th = (struct tcphdr *)(skb->data + iph->ihl * 4);
+
+ *tcpudp_hdr = th;
+ *ip_hdr = iph;
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ return 0;
+fail:
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ return -1;
+}
+
+static int efx_get_frag_hdr(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
+ void *priv)
+{
+ struct efx_channel *channel = (struct efx_channel *)priv;
+ struct ethhdr *eh;
+ struct iphdr *iph;
+
+ /* We support EtherII and VLAN encapsulated IPv4 */
+ eh = (struct ethhdr *)(page_address(frag->page) + frag->page_offset);
+ *mac_hdr = eh;
+
+ if (eh->h_proto == htons(ETH_P_IP)) {
+ iph = (struct iphdr *)(eh + 1);
+ } else {
+ struct vlan_ethhdr *veh = (struct vlan_ethhdr *)eh;
+ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+ goto fail;
+
+ iph = (struct iphdr *)(veh + 1);
+ }
+ *ip_hdr = iph;
+
+ /* We can only do LRO over TCP */
+ if (iph->protocol != IPPROTO_TCP)
+ goto fail;
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *tcpudp_hdr = (struct tcphdr *)((u8 *) iph + iph->ihl * 4);
+
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ return 0;
+ fail:
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ return -1;
+}
+
+int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx)
+{
+ size_t s = sizeof(struct net_lro_desc) * EFX_MAX_LRO_DESCRIPTORS;
+ struct net_lro_desc *lro_arr;
+
+ /* Allocate the LRO descriptors structure */
+ lro_arr = kzalloc(s, GFP_KERNEL);
+ if (lro_arr == NULL)
+ return -ENOMEM;
+
+ lro_mgr->lro_arr = lro_arr;
+ lro_mgr->max_desc = EFX_MAX_LRO_DESCRIPTORS;
+ lro_mgr->max_aggr = EFX_MAX_LRO_AGGR;
+ lro_mgr->frag_align_pad = EFX_PAGE_SKB_ALIGN;
+
+ lro_mgr->get_skb_header = efx_lro_get_skb_hdr;
+ lro_mgr->get_frag_header = efx_get_frag_hdr;
+ lro_mgr->dev = efx->net_dev;
+
+ lro_mgr->features = LRO_F_NAPI;
+
+ /* We can pass packets up with the checksum intact */
+ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
+ return 0;
+}
+
+void efx_lro_fini(struct net_lro_mgr *lro_mgr)
+{
+ kfree(lro_mgr->lro_arr);
+ lro_mgr->lro_arr = NULL;
+}
+
+/**
+ * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
+ *
+ * @rx_queue: Efx RX queue
+ * @rx_buf: RX buffer structure to populate
+ *
+ * This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information. Return a negative error code or 0 on success.
+ */
+static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct net_device *net_dev = efx->net_dev;
+ int skb_len = efx->rx_buffer_len;
+
+ rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
+ if (unlikely(!rx_buf->skb))
+ return -ENOMEM;
+
+ /* Adjust the SKB for padding and checksum */
+ skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+ rx_buf->len = skb_len - NET_IP_ALIGN;
+ rx_buf->data = (char *)rx_buf->skb->data;
+ rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_buf->dma_addr = pci_map_single(efx->pci_dev,
+ rx_buf->data, rx_buf->len,
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
+ *
+ * @rx_queue: Efx RX queue
+ * @rx_buf: RX buffer structure to populate
+ *
+ * This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information. Return a negative error code or 0 on success.
+ */
+static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ int bytes, space, offset;
+
+ bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+
+ /* If there is space left in the previously allocated page,
+ * then use it. Otherwise allocate a new one */
+ rx_buf->page = rx_queue->buf_page;
+ if (rx_buf->page == NULL) {
+ dma_addr_t dma_addr;
+
+ rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+ efx->rx_buffer_order);
+ if (unlikely(rx_buf->page == NULL))
+ return -ENOMEM;
+
+ dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
+ 0, RX_PAGE_SIZE(efx),
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(dma_addr))) {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ return -EIO;
+ }
+
+ rx_queue->buf_page = rx_buf->page;
+ rx_queue->buf_dma_addr = dma_addr;
+ rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
+ EFX_PAGE_IP_ALIGN);
+ }
+
+ offset = RX_DATA_OFFSET(rx_queue->buf_data);
+ rx_buf->len = bytes;
+ rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
+ rx_buf->data = rx_queue->buf_data;
+
+ /* Try to pack multiple buffers per page */
+ if (efx->rx_buffer_order == 0) {
+ /* The next buffer starts on the next 512 byte boundary */
+ rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
+ offset += ((bytes + 0x1ff) & ~0x1ff);
+
+ space = RX_PAGE_SIZE(efx) - offset;
+ if (space >= bytes) {
+ /* Refs dropped on kernel releasing each skb */
+ get_page(rx_queue->buf_page);
+ goto out;
+ }
+ }
+
+ /* This is the final RX buffer for this page, so mark it for
+ * unmapping */
+ rx_queue->buf_page = NULL;
+ rx_buf->unmap_addr = rx_queue->buf_dma_addr;
+
+ out:
+ return 0;
+}
+
+/* This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information.
+ */
+static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *new_rx_buf)
+{
+ int rc = 0;
+
+ if (rx_queue->channel->rx_alloc_push_pages) {
+ new_rx_buf->skb = NULL;
+ rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
+ rx_queue->alloc_page_count++;
+ } else {
+ new_rx_buf->page = NULL;
+ rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
+ rx_queue->alloc_skb_count++;
+ }
+
+ if (unlikely(rc < 0))
+ EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
+ rx_queue->queue, rc);
+ return rc;
+}
+
+static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf)
+{
+ if (rx_buf->page) {
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ if (rx_buf->unmap_addr) {
+ pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
+ RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
+ rx_buf->unmap_addr = 0;
+ }
+ } else if (likely(rx_buf->skb)) {
+ pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
+ rx_buf->len, PCI_DMA_FROMDEVICE);
+ }
+}
+
+static inline void efx_free_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf)
+{
+ if (rx_buf->page) {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ } else if (likely(rx_buf->skb)) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ }
+}
+
+static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
+ efx_free_rx_buffer(rx_queue->efx, rx_buf);
+}
+
+/**
+ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
+ * @rx_queue: RX descriptor queue
+ * @retry: Recheck the fill level
+ * This will aim to fill the RX descriptor queue up to
+ * @rx_queue->@fast_fill_limit. If there is insufficient atomic
+ * memory to do so, the caller should retry.
+ */
+static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
+ int retry)
+{
+ struct efx_rx_buffer *rx_buf;
+ unsigned fill_level, index;
+ int i, space, rc = 0;
+
+ /* Calculate current fill level. Do this outside the lock,
+ * because most of the time we'll end up not wanting to do the
+ * fill anyway.
+ */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count);
+ EFX_BUG_ON_PARANOID(fill_level >
+ rx_queue->efx->type->rxd_ring_mask + 1);
+
+ /* Don't fill if we don't need to */
+ if (fill_level >= rx_queue->fast_fill_trigger)
+ return 0;
+
+ /* Record minimum fill level */
+ if (unlikely(fill_level < rx_queue->min_fill))
+ if (fill_level)
+ rx_queue->min_fill = fill_level;
+
+ /* Acquire RX add lock. If this lock is contended, then a fast
+ * fill must already be in progress (e.g. in the refill
+ * tasklet), so we don't need to do anything
+ */
+ if (!spin_trylock_bh(&rx_queue->add_lock))
+ return -1;
+
+ retry:
+ /* Recalculate current fill level now that we have the lock */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count);
+ EFX_BUG_ON_PARANOID(fill_level >
+ rx_queue->efx->type->rxd_ring_mask + 1);
+ space = rx_queue->fast_fill_limit - fill_level;
+ if (space < EFX_RX_BATCH)
+ goto out_unlock;
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
+ " level %d to level %d using %s allocation\n",
+ rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
+ rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
+
+ do {
+ for (i = 0; i < EFX_RX_BATCH; ++i) {
+ index = (rx_queue->added_count &
+ rx_queue->efx->type->rxd_ring_mask);
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ rc = efx_init_rx_buffer(rx_queue, rx_buf);
+ if (unlikely(rc))
+ goto out;
+ ++rx_queue->added_count;
+ }
+ } while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
+ "to level %d\n", rx_queue->queue,
+ rx_queue->added_count - rx_queue->removed_count);
+
+ out:
+ /* Send write pointer to card. */
+ falcon_notify_rx_desc(rx_queue);
+
+ /* If the fast fill is running inside from the refill tasklet, then
+ * for SMP systems it may be running on a different CPU to
+ * RX event processing, which means that the fill level may now be
+ * out of date. */
+ if (unlikely(retry && (rc == 0)))
+ goto retry;
+
+ out_unlock:
+ spin_unlock_bh(&rx_queue->add_lock);
+
+ return rc;
+}
+
+/**
+ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
+ * @rx_queue: RX descriptor queue
+ *
+ * This will aim to fill the RX descriptor queue up to
+ * @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
+ * it will schedule a work item to immediately continue the fast fill
+ */
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
+{
+ int rc;
+
+ rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
+ if (unlikely(rc)) {
+ /* Schedule the work item to run immediately. The hope is
+ * that work is immediately pending to free some memory
+ * (e.g. an RX event or TX completion)
+ */
+ efx_schedule_slow_fill(rx_queue, 0);
+ }
+}
+
+void efx_rx_work(struct work_struct *data)
+{
+ struct efx_rx_queue *rx_queue;
+ int rc;
+
+ rx_queue = container_of(data, struct efx_rx_queue, work.work);
+
+ if (unlikely(!rx_queue->channel->enabled))
+ return;
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
+ "%d\n", rx_queue->queue, raw_smp_processor_id());
+
+ ++rx_queue->slow_fill_count;
+ /* Push new RX descriptors, allowing at least 1 jiffy for
+ * the kernel to free some more memory. */
+ rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
+ if (rc)
+ efx_schedule_slow_fill(rx_queue, 1);
+}
+
+static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf,
+ int len, int *discard,
+ int *leak_packet)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
+
+ if (likely(len <= max_len))
+ return;
+
+ /* The packet must be discarded, but this is only a fatal error
+ * if the caller indicated it was
+ */
+ *discard = 1;
+
+ if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
+ EFX_ERR_RL(efx, " RX queue %d seriously overlength "
+ "RX event (0x%x > 0x%x+0x%x). Leaking\n",
+ rx_queue->queue, len, max_len,
+ efx->type->rx_buffer_padding);
+ /* If this buffer was skb-allocated, then the meta
+ * data at the end of the skb will be trashed. So
+ * we have no choice but to leak the fragment.
+ */
+ *leak_packet = (rx_buf->skb != NULL);
+ efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
+ } else {
+ EFX_ERR_RL(efx, " RX queue %d overlength RX event "
+ "(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
+ }
+
+ rx_queue->channel->n_rx_overlength++;
+}
+
+/* Pass a received packet up through the generic LRO stack
+ *
+ * Handles driverlink veto, and passes the fragment up via
+ * the appropriate LRO method
+ */
+static inline void efx_rx_packet_lro(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct net_lro_mgr *lro_mgr = &channel->lro_mgr;
+ void *priv = channel;
+
+ /* Pass the skb/page into the LRO engine */
+ if (rx_buf->page) {
+ struct skb_frag_struct frags;
+
+ frags.page = rx_buf->page;
+ frags.page_offset = RX_BUF_OFFSET(rx_buf);
+ frags.size = rx_buf->len;
+
+ lro_receive_frags(lro_mgr, &frags, rx_buf->len,
+ rx_buf->len, priv, 0);
+
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ rx_buf->page = NULL;
+ } else {
+ EFX_BUG_ON_PARANOID(!rx_buf->skb);
+
+ lro_receive_skb(lro_mgr, rx_buf->skb, priv);
+ rx_buf->skb = NULL;
+ }
+}
+
+/* Allocate and construct an SKB around a struct page.*/
+static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
+ struct efx_nic *efx,
+ int hdr_len)
+{
+ struct sk_buff *skb;
+
+ /* Allocate an SKB to store the headers */
+ skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
+ if (unlikely(skb == NULL)) {
+ EFX_ERR_RL(efx, "RX out of memory for skb\n");
+ return NULL;
+ }
+
+ EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags);
+ EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
+
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
+
+ skb->len = rx_buf->len;
+ skb->truesize = rx_buf->len + sizeof(struct sk_buff);
+ memcpy(skb->data, rx_buf->data, hdr_len);
+ skb->tail += hdr_len;
+
+ /* Append the remaining page onto the frag list */
+ if (unlikely(rx_buf->len > hdr_len)) {
+ struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
+ frag->page = rx_buf->page;
+ frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
+ frag->size = skb->len - hdr_len;
+ skb_shinfo(skb)->nr_frags = 1;
+ skb->data_len = frag->size;
+ } else {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ skb->data_len = 0;
+ }
+
+ /* Ownership has transferred from the rx_buf to skb */
+ rx_buf->page = NULL;
+
+ /* Move past the ethernet header */
+ skb->protocol = eth_type_trans(skb, efx->net_dev);
+
+ return skb;
+}
+
+void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+ unsigned int len, int checksummed, int discard)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct efx_rx_buffer *rx_buf;
+ int leak_packet = 0;
+
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ EFX_BUG_ON_PARANOID(!rx_buf->data);
+ EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page);
+ EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page));
+
+ /* This allows the refill path to post another buffer.
+ * EFX_RXD_HEAD_ROOM ensures that the slot we are using
+ * isn't overwritten yet.
+ */
+ rx_queue->removed_count++;
+
+ /* Validate the length encoded in the event vs the descriptor pushed */
+ efx_rx_packet__check_len(rx_queue, rx_buf, len,
+ &discard, &leak_packet);
+
+ EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
+ rx_queue->queue, index,
+ (unsigned long long)rx_buf->dma_addr, len,
+ (checksummed ? " [SUMMED]" : ""),
+ (discard ? " [DISCARD]" : ""));
+
+ /* Discard packet, if instructed to do so */
+ if (unlikely(discard)) {
+ if (unlikely(leak_packet))
+ rx_queue->channel->n_skbuff_leaks++;
+ else
+ /* We haven't called efx_unmap_rx_buffer yet,
+ * so fini the entire rx_buffer here */
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ return;
+ }
+
+ /* Release card resources - assumes all RX buffers consumed in-order
+ * per RX queue
+ */
+ efx_unmap_rx_buffer(efx, rx_buf);
+
+ /* Prefetch nice and early so data will (hopefully) be in cache by
+ * the time we look at it.
+ */
+ prefetch(rx_buf->data);
+
+ /* Pipeline receives so that we give time for packet headers to be
+ * prefetched into cache.
+ */
+ rx_buf->len = len;
+ if (rx_queue->channel->rx_pkt)
+ __efx_rx_packet(rx_queue->channel,
+ rx_queue->channel->rx_pkt,
+ rx_queue->channel->rx_pkt_csummed);
+ rx_queue->channel->rx_pkt = rx_buf;
+ rx_queue->channel->rx_pkt_csummed = checksummed;
+}
+
+/* Handle a received packet. Second half: Touches packet payload. */
+void __efx_rx_packet(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf, int checksummed)
+{
+ struct efx_nic *efx = channel->efx;
+ struct sk_buff *skb;
+ int lro = efx->net_dev->features & NETIF_F_LRO;
+
+ if (rx_buf->skb) {
+ prefetch(skb_shinfo(rx_buf->skb));
+
+ skb_put(rx_buf->skb, rx_buf->len);
+
+ /* Move past the ethernet header. rx_buf->data still points
+ * at the ethernet header */
+ rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
+ efx->net_dev);
+ }
+
+ /* Both our generic-LRO and SFC-SSR support skb and page based
+ * allocation, but neither support switching from one to the
+ * other on the fly. If we spot that the allocation mode has
+ * changed, then flush the LRO state.
+ */
+ if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
+ efx_flush_lro(channel);
+ channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
+ }
+ if (likely(checksummed && lro)) {
+ efx_rx_packet_lro(channel, rx_buf);
+ goto done;
+ }
+
+ /* Form an skb if required */
+ if (rx_buf->page) {
+ int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
+ skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
+ if (unlikely(skb == NULL)) {
+ efx_free_rx_buffer(efx, rx_buf);
+ goto done;
+ }
+ } else {
+ /* We now own the SKB */
+ skb = rx_buf->skb;
+ rx_buf->skb = NULL;
+ }
+
+ EFX_BUG_ON_PARANOID(rx_buf->page);
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ EFX_BUG_ON_PARANOID(!skb);
+
+ /* Set the SKB flags */
+ if (unlikely(!checksummed || !efx->rx_checksum_enabled))
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Pass the packet up */
+ netif_receive_skb(skb);
+
+ /* Update allocation strategy method */
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+
+ /* fall-thru */
+done:
+ efx->net_dev->last_rx = jiffies;
+}
+
+void efx_rx_strategy(struct efx_channel *channel)
+{
+ enum efx_rx_alloc_method method = rx_alloc_method;
+
+ /* Only makes sense to use page based allocation if LRO is enabled */
+ if (!(channel->efx->net_dev->features & NETIF_F_LRO)) {
+ method = RX_ALLOC_METHOD_SKB;
+ } else if (method == RX_ALLOC_METHOD_AUTO) {
+ /* Constrain the rx_alloc_level */
+ if (channel->rx_alloc_level < 0)
+ channel->rx_alloc_level = 0;
+ else if (channel->rx_alloc_level > RX_ALLOC_LEVEL_MAX)
+ channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
+
+ /* Decide on the allocation method */
+ method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_LRO) ?
+ RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
+ }
+
+ /* Push the option */
+ channel->rx_alloc_push_pages = (method == RX_ALLOC_METHOD_PAGE);
+}
+
+int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int rxq_size;
+ int rc;
+
+ EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
+
+ /* Allocate RX buffers */
+ rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
+ rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
+ if (!rx_queue->buffer) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ rc = falcon_probe_rx(rx_queue);
+ if (rc)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ kfree(rx_queue->buffer);
+ rx_queue->buffer = NULL;
+ fail1:
+ rx_queue->used = 0;
+
+ return rc;
+}
+
+int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int max_fill, trigger, limit;
+
+ EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
+
+ /* Initialise ptr fields */
+ rx_queue->added_count = 0;
+ rx_queue->notified_count = 0;
+ rx_queue->removed_count = 0;
+ rx_queue->min_fill = -1U;
+ rx_queue->min_overfill = -1U;
+
+ /* Initialise limit fields */
+ max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
+ trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
+ limit = max_fill * min(rx_refill_limit, 100U) / 100U;
+
+ rx_queue->max_fill = max_fill;
+ rx_queue->fast_fill_trigger = trigger;
+ rx_queue->fast_fill_limit = limit;
+
+ /* Set up RX descriptor ring */
+ return falcon_init_rx(rx_queue);
+}
+
+void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ int i;
+ struct efx_rx_buffer *rx_buf;
+
+ EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+
+ falcon_fini_rx(rx_queue);
+
+ /* Release RX buffers NB start at index 0 not current HW ptr */
+ if (rx_queue->buffer) {
+ for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
+ rx_buf = efx_rx_buffer(rx_queue, i);
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ }
+ }
+
+ /* For a page that is part-way through splitting into RX buffers */
+ if (rx_queue->buf_page != NULL) {
+ pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
+ RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
+ __free_pages(rx_queue->buf_page,
+ rx_queue->efx->rx_buffer_order);
+ rx_queue->buf_page = NULL;
+ }
+}
+
+void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
+
+ falcon_remove_rx(rx_queue);
+
+ kfree(rx_queue->buffer);
+ rx_queue->buffer = NULL;
+ rx_queue->used = 0;
+}
+
+void efx_flush_lro(struct efx_channel *channel)
+{
+ lro_flush_all(&channel->lro_mgr);
+}
+
+
+module_param(rx_alloc_method, int, 0644);
+MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
+
+module_param(rx_refill_threshold, uint, 0444);
+MODULE_PARM_DESC(rx_refill_threshold,
+ "RX descriptor ring fast/slow fill threshold (%)");
+
diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h
new file mode 100644
index 00000000000..f35e377bfc5
--- /dev/null
+++ b/drivers/net/sfc/rx.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_RX_H
+#define EFX_RX_H
+
+#include "net_driver.h"
+
+int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
+int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
+
+int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx);
+void efx_lro_fini(struct net_lro_mgr *lro_mgr);
+void efx_flush_lro(struct efx_channel *channel);
+void efx_rx_strategy(struct efx_channel *channel);
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
+void efx_rx_work(struct work_struct *data);
+void __efx_rx_packet(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf, int checksummed);
+
+#endif /* EFX_RX_H */
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
new file mode 100644
index 00000000000..11fa9fb8f48
--- /dev/null
+++ b/drivers/net/sfc/sfe4001.c
@@ -0,0 +1,252 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+/*****************************************************************************
+ * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
+ * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
+ * the PHY
+ */
+#include <linux/delay.h>
+#include "efx.h"
+#include "phy.h"
+#include "boards.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "mac.h"
+
+/**************************************************************************
+ *
+ * I2C IO Expander device
+ *
+ **************************************************************************/
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_INVERT 0x04
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_SHORTEN_JTAG_LBN 5
+#define P0_SHORTEN_JTAG_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+#define P0_DSP_RESET_LBN 7
+#define P0_DSP_RESET_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_OUT 0x03
+#define P1_INVERT 0x05
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_RESERVED_LBN 2
+#define P1_RESERVED_WIDTH 2
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+
+/**************************************************************************
+ *
+ * Temperature Sensor
+ *
+ **************************************************************************/
+#define MAX6647 0x4e
+
+#define RLTS 0x00
+#define RLTE 0x01
+#define RSL 0x02
+#define RCL 0x03
+#define RCRA 0x04
+#define RLHN 0x05
+#define RLLI 0x06
+#define RRHI 0x07
+#define RRLS 0x08
+#define WCRW 0x0a
+#define WLHO 0x0b
+#define WRHA 0x0c
+#define WRLN 0x0e
+#define OSHT 0x0f
+#define REET 0x10
+#define RIET 0x11
+#define RWOE 0x19
+#define RWOI 0x20
+#define HYS 0x21
+#define QUEUE 0x22
+#define MFID 0xfe
+#define REVID 0xff
+
+/* Status bits */
+#define MAX6647_BUSY (1 << 7) /* ADC is converting */
+#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
+#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
+#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
+#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
+#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
+#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
+#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
+
+static const u8 xgphy_max_temperature = 90;
+
+void sfe4001_poweroff(struct efx_nic *efx)
+{
+ struct efx_i2c_interface *i2c = &efx->i2c;
+
+ u8 cfg, out, in;
+
+ EFX_INFO(efx, "%s\n", __func__);
+
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+
+ /* Disable port 1 outputs on IO expander */
+ cfg = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+
+ /* Disable port 0 outputs on IO expander */
+ cfg = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+
+ /* Clear any over-temperature alert */
+ (void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+}
+
+/* This board uses an I2C expander to provider power to the PHY, which needs to
+ * be turned on before the PHY can be used.
+ * Context: Process context, rtnl lock held
+ */
+int sfe4001_poweron(struct efx_nic *efx)
+{
+ struct efx_i2c_interface *i2c = &efx->i2c;
+ unsigned int count;
+ int rc;
+ u8 out, in, cfg;
+ efx_dword_t reg;
+
+ /* 10Xpress has fixed-function LED pins, so there is no board-specific
+ * blink code. */
+ efx->board_info.blink = tenxpress_phy_blink;
+
+ /* Ensure that XGXS and XAUI SerDes are held in reset */
+ EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
+ XX_PWRDNB_EN, 1,
+ XX_RSTPLLAB_EN, 1,
+ XX_RESETA_EN, 1,
+ XX_RESETB_EN, 1,
+ XX_RSTXGXSRX_EN, 1,
+ XX_RSTXGXSTX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Set DSP over-temperature alert threshold */
+ EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
+ rc = efx_i2c_write(i2c, MAX6647, WLHO,
+ &xgphy_max_temperature, 1);
+ if (rc)
+ goto fail1;
+
+ /* Read it back and verify */
+ rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
+ if (rc)
+ goto fail1;
+ if (in != xgphy_max_temperature) {
+ rc = -EFAULT;
+ goto fail1;
+ }
+
+ /* Clear any previous over-temperature alert */
+ rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+ if (rc)
+ goto fail1;
+
+ /* Enable port 0 and port 1 outputs on IO expander */
+ cfg = 0x00;
+ rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+ if (rc)
+ goto fail1;
+ cfg = 0xff & ~(1 << P1_SPARE_LBN);
+ rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+ if (rc)
+ goto fail2;
+
+ /* Turn all power off then wait 1 sec. This ensures PHY is reset */
+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+ (0 << P0_EN_1V0X_LBN));
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+
+ schedule_timeout_uninterruptible(HZ);
+ count = 0;
+ do {
+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+ out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+ (1 << P0_X_TRST_LBN));
+
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+ msleep(10);
+
+ /* Turn on 1V power rail */
+ out &= ~(1 << P0_EN_1V0X_LBN);
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+
+ EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
+
+ schedule_timeout_uninterruptible(HZ);
+
+ /* Check DSP is powered */
+ rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
+ if (rc)
+ goto fail3;
+ if (in & (1 << P1_AFE_PWD_LBN))
+ goto done;
+
+ } while (++count < 20);
+
+ EFX_INFO(efx, "timed out waiting for power\n");
+ rc = -ETIMEDOUT;
+ goto fail3;
+
+done:
+ EFX_INFO(efx, "PHY is powered on\n");
+ return 0;
+
+fail3:
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ /* Disable port 1 outputs on IO expander */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
+fail2:
+ /* Disable port 0 outputs on IO expander */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
+fail1:
+ return rc;
+}
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
new file mode 100644
index 00000000000..34412f3d41c
--- /dev/null
+++ b/drivers/net/sfc/spi.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_SPI_H
+#define EFX_SPI_H
+
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Basic SPI command set and bit definitions
+ *
+ *************************************************************************/
+
+/*
+ * Commands common to all known devices.
+ *
+ */
+
+/* Write status register */
+#define SPI_WRSR 0x01
+
+/* Write data to memory array */
+#define SPI_WRITE 0x02
+
+/* Read data from memory array */
+#define SPI_READ 0x03
+
+/* Reset write enable latch */
+#define SPI_WRDI 0x04
+
+/* Read status register */
+#define SPI_RDSR 0x05
+
+/* Set write enable latch */
+#define SPI_WREN 0x06
+
+/* SST: Enable write to status register */
+#define SPI_SST_EWSR 0x50
+
+/*
+ * Status register bits. Not all bits are supported on all devices.
+ *
+ */
+
+/* Write-protect pin enabled */
+#define SPI_STATUS_WPEN 0x80
+
+/* Block protection bit 2 */
+#define SPI_STATUS_BP2 0x10
+
+/* Block protection bit 1 */
+#define SPI_STATUS_BP1 0x08
+
+/* Block protection bit 0 */
+#define SPI_STATUS_BP0 0x04
+
+/* State of the write enable latch */
+#define SPI_STATUS_WEN 0x02
+
+/* Device busy flag */
+#define SPI_STATUS_NRDY 0x01
+
+#endif /* EFX_SPI_H */
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
new file mode 100644
index 00000000000..a2e9f79e47b
--- /dev/null
+++ b/drivers/net/sfc/tenxpress.c
@@ -0,0 +1,434 @@
+/****************************************************************************
+ * Driver for Solarflare 802.3an compliant PHY
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include "efx.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "falcon.h"
+#include "phy.h"
+#include "falcon_hwdefs.h"
+#include "boards.h"
+#include "mac.h"
+
+/* We expect these MMDs to be in the package */
+/* AN not here as mdio_check_mmds() requires STAT2 support */
+#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PHYXS)
+
+/* We complain if we fail to see the link partner as 10G capable this many
+ * times in a row (must be > 1 as sampling the autoneg. registers is racy)
+ */
+#define MAX_BAD_LP_TRIES (5)
+
+/* Extended control register */
+#define PMA_PMD_XCONTROL_REG 0xc000
+#define PMA_PMD_LNPGA_POWERDOWN_LBN 8
+#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
+
+/* extended status register */
+#define PMA_PMD_XSTATUS_REG 0xc001
+#define PMA_PMD_XSTAT_FLP_LBN (12)
+
+/* LED control register */
+#define PMA_PMD_LED_CTRL_REG (0xc007)
+#define PMA_PMA_LED_ACTIVITY_LBN (3)
+
+/* LED function override register */
+#define PMA_PMD_LED_OVERR_REG (0xc009)
+/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
+#define PMA_PMD_LED_LINK_LBN (0)
+#define PMA_PMD_LED_SPEED_LBN (2)
+#define PMA_PMD_LED_TX_LBN (4)
+#define PMA_PMD_LED_RX_LBN (6)
+/* Override settings */
+#define PMA_PMD_LED_AUTO (0) /* H/W control */
+#define PMA_PMD_LED_ON (1)
+#define PMA_PMD_LED_OFF (2)
+#define PMA_PMD_LED_FLASH (3)
+/* All LEDs under hardware control */
+#define PMA_PMD_LED_FULL_AUTO (0)
+/* Green and Amber under hardware control, Red off */
+#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
+
+
+/* Self test (BIST) control register */
+#define PMA_PMD_BIST_CTRL_REG (0xc014)
+#define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */
+#define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */
+#define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */
+/* Self test status register */
+#define PMA_PMD_BIST_STAT_REG (0xc015)
+#define PMA_PMD_BIST_ENX_LBN (3)
+#define PMA_PMD_BIST_PMA_LBN (2)
+#define PMA_PMD_BIST_RXD_LBN (1)
+#define PMA_PMD_BIST_AFE_LBN (0)
+
+#define BIST_MAX_DELAY (1000)
+#define BIST_POLL_DELAY (10)
+
+/* Misc register defines */
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
+#define CLK312_EN_LBN 3
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG (0xd000)
+#define PCS_BOOT_FATAL_ERR_LBN (0)
+#define PCS_BOOT_PROGRESS_LBN (1)
+#define PCS_BOOT_PROGRESS_WIDTH (2)
+#define PCS_BOOT_COMPLETE_LBN (3)
+#define PCS_BOOT_MAX_DELAY (100)
+#define PCS_BOOT_POLL_DELAY (10)
+
+/* Time to wait between powering down the LNPGA and turning off the power
+ * rails */
+#define LNPGA_PDOWN_WAIT (HZ / 5)
+
+static int crc_error_reset_threshold = 100;
+module_param(crc_error_reset_threshold, int, 0644);
+MODULE_PARM_DESC(crc_error_reset_threshold,
+ "Max number of CRC errors before XAUI reset");
+
+struct tenxpress_phy_data {
+ enum tenxpress_state state;
+ atomic_t bad_crc_count;
+ int bad_lp_tries;
+};
+
+static int tenxpress_state_is(struct efx_nic *efx, int state)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ return (phy_data != NULL) && (state == phy_data->state);
+}
+
+void tenxpress_set_state(struct efx_nic *efx,
+ enum tenxpress_state state)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ if (phy_data != NULL)
+ phy_data->state = state;
+}
+
+void tenxpress_crc_err(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ if (phy_data != NULL)
+ atomic_inc(&phy_data->bad_crc_count);
+}
+
+/* Check that the C166 has booted successfully */
+static int tenxpress_phy_check(struct efx_nic *efx)
+{
+ int phy_id = efx->mii.phy_id;
+ int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
+ int boot_stat;
+
+ /* Wait for the boot to complete (or not) */
+ while (count) {
+ boot_stat = mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_PCS,
+ PCS_BOOT_STATUS_REG);
+ if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
+ break;
+ count--;
+ udelay(PCS_BOOT_POLL_DELAY);
+ }
+
+ if (!count) {
+ EFX_ERR(efx, "%s: PHY boot timed out. Last status "
+ "%x\n", __func__,
+ (boot_stat >> PCS_BOOT_PROGRESS_LBN) &
+ ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void tenxpress_reset_xaui(struct efx_nic *efx);
+
+static int tenxpress_init(struct efx_nic *efx)
+{
+ int rc, reg;
+
+ /* Turn on the clock */
+ reg = (1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id,
+ MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+ rc = tenxpress_phy_check(efx);
+ if (rc < 0)
+ return rc;
+
+ /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
+ reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_CTRL_REG, reg);
+
+ reg = PMA_PMD_LED_DEFAULT;
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+
+ return rc;
+}
+
+static int tenxpress_phy_init(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data;
+ int rc = 0;
+
+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+ efx->phy_data = phy_data;
+
+ tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
+
+ rc = mdio_clause45_wait_reset_mmds(efx,
+ TENXPRESS_REQUIRED_DEVS);
+ if (rc < 0)
+ goto fail;
+
+ rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+ if (rc < 0)
+ goto fail;
+
+ rc = tenxpress_init(efx);
+ if (rc < 0)
+ goto fail;
+
+ schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
+
+ /* Let XGXS and SerDes out of reset and resets 10XPress */
+ falcon_reset_xaui(efx);
+
+ return 0;
+
+ fail:
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+ return rc;
+}
+
+static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
+{
+ struct tenxpress_phy_data *pd = efx->phy_data;
+ int reg;
+
+ /* Nothing to do if all is well and was previously so. */
+ if (!(bad_lp || pd->bad_lp_tries))
+ return;
+
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
+
+ if (bad_lp)
+ pd->bad_lp_tries++;
+ else
+ pd->bad_lp_tries = 0;
+
+ if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
+ pd->bad_lp_tries = 0; /* Restart count */
+ reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
+ reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
+ EFX_ERR(efx, "This NIC appears to be plugged into"
+ " a port that is not 10GBASE-T capable.\n"
+ " This PHY is 10GBASE-T ONLY, so no link can"
+ " be established.\n");
+ } else {
+ reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
+ }
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+}
+
+/* Check link status and return a boolean OK value. If the link is NOT
+ * OK we have a quick rummage round to see if we appear to be plugged
+ * into a non-10GBT port and if so warn the user that they won't get
+ * link any time soon as we are 10GBT only, unless caller specified
+ * not to do this check (it isn't useful in loopback) */
+static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
+{
+ int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
+
+ if (ok) {
+ tenxpress_set_bad_lp(efx, 0);
+ } else if (check_lp) {
+ /* Are we plugged into the wrong sort of link? */
+ int bad_lp = 0;
+ int phy_id = efx->mii.phy_id;
+ int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+ MDIO_AN_STATUS);
+ int xphy_stat = mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_PMAPMD,
+ PMA_PMD_XSTATUS_REG);
+ /* Are we plugged into anything that sends FLPs? If
+ * not we can't distinguish between not being plugged
+ * in and being plugged into a non-AN antique. The FLP
+ * bit has the advantage of not clearing when autoneg
+ * restarts. */
+ if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
+ tenxpress_set_bad_lp(efx, 0);
+ return ok;
+ }
+
+ /* If it can do 10GBT it must be XNP capable */
+ bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
+ if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
+ bad_lp = !(mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
+ (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
+ }
+ tenxpress_set_bad_lp(efx, bad_lp);
+ }
+ return ok;
+}
+
+static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+{
+ if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
+ return;
+
+ efx->link_up = tenxpress_link_ok(efx, 0);
+ efx->link_options = GM_LPA_10000FULL;
+}
+
+static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
+{
+ /* Nothing done here - LASI interrupts aren't reliable so poll */
+}
+
+
+/* Poll PHY for interrupt */
+static int tenxpress_phy_check_hw(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
+ int link_ok;
+
+ link_ok = phy_up && tenxpress_link_ok(efx, 1);
+
+ if (link_ok != efx->link_up)
+ falcon_xmac_sim_phy_event(efx);
+
+ /* Nothing to check if we've already shut down the PHY */
+ if (!phy_up)
+ return 0;
+
+ if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
+ EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
+ falcon_reset_xaui(efx);
+ atomic_set(&phy_data->bad_crc_count, 0);
+ }
+
+ return 0;
+}
+
+static void tenxpress_phy_fini(struct efx_nic *efx)
+{
+ int reg;
+
+ /* Power down the LNPGA */
+ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_XCONTROL_REG, reg);
+
+ /* Waiting here ensures that the board fini, which can turn off the
+ * power to the PHY, won't get run until the LNPGA powerdown has been
+ * given long enough to complete. */
+ schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+}
+
+
+/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
+ * (which probably aren't wired anyway) are left in AUTO mode */
+void tenxpress_phy_blink(struct efx_nic *efx, int blink)
+{
+ int reg;
+
+ if (blink)
+ reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
+ (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
+ (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
+ else
+ reg = PMA_PMD_LED_DEFAULT;
+
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+}
+
+static void tenxpress_reset_xaui(struct efx_nic *efx)
+{
+ int phy = efx->mii.phy_id;
+ int clk_ctrl, test_select, soft_rst2;
+
+ /* Real work is done on clock_ctrl other resets are thought to be
+ * optional but make the reset more reliable
+ */
+
+ /* Read */
+ clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG);
+ test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG);
+ soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG);
+
+ /* Put in reset */
+ test_select &= ~(1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG, test_select);
+
+ soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG, soft_rst2);
+
+ clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG, clk_ctrl);
+ udelay(10);
+
+ /* Remove reset */
+ clk_ctrl |= (1 << PLL312_RST_N_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG, clk_ctrl);
+ udelay(10);
+
+ soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG, soft_rst2);
+ udelay(10);
+
+ test_select |= (1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG, test_select);
+ udelay(10);
+}
+
+struct efx_phy_operations falcon_tenxpress_phy_ops = {
+ .init = tenxpress_phy_init,
+ .reconfigure = tenxpress_phy_reconfigure,
+ .check_hw = tenxpress_phy_check_hw,
+ .fini = tenxpress_phy_fini,
+ .clear_interrupt = tenxpress_phy_clear_interrupt,
+ .reset_xaui = tenxpress_reset_xaui,
+ .mmds = TENXPRESS_REQUIRED_DEVS,
+};
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
new file mode 100644
index 00000000000..fbb866b2185
--- /dev/null
+++ b/drivers/net/sfc/tx.c
@@ -0,0 +1,452 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/pci.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/highmem.h>
+#include "net_driver.h"
+#include "tx.h"
+#include "efx.h"
+#include "falcon.h"
+#include "workarounds.h"
+
+/*
+ * TX descriptor ring full threshold
+ *
+ * The tx_queue descriptor ring fill-level must fall below this value
+ * before we restart the netif queue
+ */
+#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \
+ (_tx_queue->efx->type->txd_ring_mask / 2u)
+
+/* We want to be able to nest calls to netif_stop_queue(), since each
+ * channel can have an individual stop on the queue.
+ */
+void efx_stop_queue(struct efx_nic *efx)
+{
+ spin_lock_bh(&efx->netif_stop_lock);
+ EFX_TRACE(efx, "stop TX queue\n");
+
+ atomic_inc(&efx->netif_stop_count);
+ netif_stop_queue(efx->net_dev);
+
+ spin_unlock_bh(&efx->netif_stop_lock);
+}
+
+/* Wake netif's TX queue
+ * We want to be able to nest calls to netif_stop_queue(), since each
+ * channel can have an individual stop on the queue.
+ */
+inline void efx_wake_queue(struct efx_nic *efx)
+{
+ local_bh_disable();
+ if (atomic_dec_and_lock(&efx->netif_stop_count,
+ &efx->netif_stop_lock)) {
+ EFX_TRACE(efx, "waking TX queue\n");
+ netif_wake_queue(efx->net_dev);
+ spin_unlock(&efx->netif_stop_lock);
+ }
+ local_bh_enable();
+}
+
+static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
+ struct efx_tx_buffer *buffer)
+{
+ if (buffer->unmap_len) {
+ struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+ if (buffer->unmap_single)
+ pci_unmap_single(pci_dev, buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ else
+ pci_unmap_page(pci_dev, buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ buffer->unmap_len = 0;
+ buffer->unmap_single = 0;
+ }
+
+ if (buffer->skb) {
+ dev_kfree_skb_any((struct sk_buff *) buffer->skb);
+ buffer->skb = NULL;
+ EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
+ "complete\n", tx_queue->queue, read_ptr);
+ }
+}
+
+
+/*
+ * Add a socket buffer to a TX queue
+ *
+ * This maps all fragments of a socket buffer for DMA and adds them to
+ * the TX queue. The queue's insert pointer will be incremented by
+ * the number of fragments in the socket buffer.
+ *
+ * If any DMA mapping fails, any mapped fragments will be unmapped,
+ * the queue's insert pointer will be restored to its original value.
+ *
+ * Returns NETDEV_TX_OK or NETDEV_TX_BUSY
+ * You must hold netif_tx_lock() to call this function.
+ */
+static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct pci_dev *pci_dev = efx->pci_dev;
+ struct efx_tx_buffer *buffer;
+ skb_frag_t *fragment;
+ struct page *page;
+ int page_offset;
+ unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
+ dma_addr_t dma_addr, unmap_addr = 0;
+ unsigned int dma_len;
+ unsigned unmap_single;
+ int q_space, i = 0;
+ int rc = NETDEV_TX_OK;
+
+ EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
+
+ /* Get size of the initial fragment */
+ len = skb_headlen(skb);
+
+ fill_level = tx_queue->insert_count - tx_queue->old_read_count;
+ q_space = efx->type->txd_ring_mask - 1 - fill_level;
+
+ /* Map for DMA. Use pci_map_single rather than pci_map_page
+ * since this is more efficient on machines with sparse
+ * memory.
+ */
+ unmap_single = 1;
+ dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+
+ /* Process all fragments */
+ while (1) {
+ if (unlikely(pci_dma_mapping_error(dma_addr)))
+ goto pci_err;
+
+ /* Store fields for marking in the per-fragment final
+ * descriptor */
+ unmap_len = len;
+ unmap_addr = dma_addr;
+
+ /* Add to TX queue, splitting across DMA boundaries */
+ do {
+ if (unlikely(q_space-- <= 0)) {
+ /* It might be that completions have
+ * happened since the xmit path last
+ * checked. Update the xmit path's
+ * copy of read_count.
+ */
+ ++tx_queue->stopped;
+ /* This memory barrier protects the
+ * change of stopped from the access
+ * of read_count. */
+ smp_mb();
+ tx_queue->old_read_count =
+ *(volatile unsigned *)
+ &tx_queue->read_count;
+ fill_level = (tx_queue->insert_count
+ - tx_queue->old_read_count);
+ q_space = (efx->type->txd_ring_mask - 1 -
+ fill_level);
+ if (unlikely(q_space-- <= 0))
+ goto stop;
+ smp_mb();
+ --tx_queue->stopped;
+ }
+
+ insert_ptr = (tx_queue->insert_count &
+ efx->type->txd_ring_mask);
+ buffer = &tx_queue->buffer[insert_ptr];
+ EFX_BUG_ON_PARANOID(buffer->skb);
+ EFX_BUG_ON_PARANOID(buffer->len);
+ EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+ EFX_BUG_ON_PARANOID(buffer->unmap_len);
+
+ dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
+ if (likely(dma_len > len))
+ dma_len = len;
+
+ misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
+ if (misalign && dma_len + misalign > 512)
+ dma_len = 512 - misalign;
+
+ /* Fill out per descriptor fields */
+ buffer->len = dma_len;
+ buffer->dma_addr = dma_addr;
+ len -= dma_len;
+ dma_addr += dma_len;
+ ++tx_queue->insert_count;
+ } while (len);
+
+ /* Transfer ownership of the unmapping to the final buffer */
+ buffer->unmap_addr = unmap_addr;
+ buffer->unmap_single = unmap_single;
+ buffer->unmap_len = unmap_len;
+ unmap_len = 0;
+
+ /* Get address and size of next fragment */
+ if (i >= skb_shinfo(skb)->nr_frags)
+ break;
+ fragment = &skb_shinfo(skb)->frags[i];
+ len = fragment->size;
+ page = fragment->page;
+ page_offset = fragment->page_offset;
+ i++;
+ /* Map for DMA */
+ unmap_single = 0;
+ dma_addr = pci_map_page(pci_dev, page, page_offset, len,
+ PCI_DMA_TODEVICE);
+ }
+
+ /* Transfer ownership of the skb to the final buffer */
+ buffer->skb = skb;
+ buffer->continuation = 0;
+
+ /* Pass off to hardware */
+ falcon_push_buffers(tx_queue);
+
+ return NETDEV_TX_OK;
+
+ pci_err:
+ EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
+ "fragments for DMA\n", tx_queue->queue, skb->len,
+ skb_shinfo(skb)->nr_frags + 1);
+
+ /* Mark the packet as transmitted, and free the SKB ourselves */
+ dev_kfree_skb_any((struct sk_buff *)skb);
+ goto unwind;
+
+ stop:
+ rc = NETDEV_TX_BUSY;
+
+ if (tx_queue->stopped == 1)
+ efx_stop_queue(efx);
+
+ unwind:
+ /* Work backwards until we hit the original insert pointer value */
+ while (tx_queue->insert_count != tx_queue->write_count) {
+ --tx_queue->insert_count;
+ insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+ buffer = &tx_queue->buffer[insert_ptr];
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->len = 0;
+ }
+
+ /* Free the fragment we were mid-way through pushing */
+ if (unmap_len)
+ pci_unmap_page(pci_dev, unmap_addr, unmap_len,
+ PCI_DMA_TODEVICE);
+
+ return rc;
+}
+
+/* Remove packets from the TX queue
+ *
+ * This removes packets from the TX queue, up to and including the
+ * specified index.
+ */
+static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
+ unsigned int index)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned int stop_index, read_ptr;
+ unsigned int mask = tx_queue->efx->type->txd_ring_mask;
+
+ stop_index = (index + 1) & mask;
+ read_ptr = tx_queue->read_count & mask;
+
+ while (read_ptr != stop_index) {
+ struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
+ if (unlikely(buffer->len == 0)) {
+ EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
+ "completion id %x\n", tx_queue->queue,
+ read_ptr);
+ efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
+ return;
+ }
+
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->continuation = 1;
+ buffer->len = 0;
+
+ ++tx_queue->read_count;
+ read_ptr = tx_queue->read_count & mask;
+ }
+}
+
+/* Initiate a packet transmission on the specified TX queue.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ *
+ * This function is split out from efx_hard_start_xmit to allow the
+ * loopback test to direct packets via specific TX queues. It is
+ * therefore a non-static inline, so as not to penalise performance
+ * for non-loopback transmissions.
+ *
+ * Context: netif_tx_lock held
+ */
+inline int efx_xmit(struct efx_nic *efx,
+ struct efx_tx_queue *tx_queue, struct sk_buff *skb)
+{
+ int rc;
+
+ /* Map fragments for DMA and add to TX queue */
+ rc = efx_enqueue_skb(tx_queue, skb);
+ if (unlikely(rc != NETDEV_TX_OK))
+ goto out;
+
+ /* Update last TX timer */
+ efx->net_dev->trans_start = jiffies;
+
+ out:
+ return rc;
+}
+
+/* Initiate a packet transmission. We use one channel per CPU
+ * (sharing when we have more CPUs than channels). On Falcon, the TX
+ * completion events will be directed back to the CPU that transmitted
+ * the packet, which should be cache-efficient.
+ *
+ * Context: non-blocking.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ */
+int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ return efx_xmit(efx, &efx->tx_queue[0], skb);
+}
+
+void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
+{
+ unsigned fill_level;
+ struct efx_nic *efx = tx_queue->efx;
+
+ EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask);
+
+ efx_dequeue_buffers(tx_queue, index);
+
+ /* See if we need to restart the netif queue. This barrier
+ * separates the update of read_count from the test of
+ * stopped. */
+ smp_mb();
+ if (unlikely(tx_queue->stopped)) {
+ fill_level = tx_queue->insert_count - tx_queue->read_count;
+ if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
+ EFX_BUG_ON_PARANOID(!NET_DEV_REGISTERED(efx));
+
+ /* Do this under netif_tx_lock(), to avoid racing
+ * with efx_xmit(). */
+ netif_tx_lock(efx->net_dev);
+ if (tx_queue->stopped) {
+ tx_queue->stopped = 0;
+ efx_wake_queue(efx);
+ }
+ netif_tx_unlock(efx->net_dev);
+ }
+ }
+}
+
+int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned int txq_size;
+ int i, rc;
+
+ EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
+
+ /* Allocate software ring */
+ txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
+ tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
+ if (!tx_queue->buffer) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+ for (i = 0; i <= efx->type->txd_ring_mask; ++i)
+ tx_queue->buffer[i].continuation = 1;
+
+ /* Allocate hardware ring */
+ rc = falcon_probe_tx(tx_queue);
+ if (rc)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ kfree(tx_queue->buffer);
+ tx_queue->buffer = NULL;
+ fail1:
+ tx_queue->used = 0;
+
+ return rc;
+}
+
+int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
+
+ tx_queue->insert_count = 0;
+ tx_queue->write_count = 0;
+ tx_queue->read_count = 0;
+ tx_queue->old_read_count = 0;
+ BUG_ON(tx_queue->stopped);
+
+ /* Set up TX descriptor ring */
+ return falcon_init_tx(tx_queue);
+}
+
+void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
+{
+ struct efx_tx_buffer *buffer;
+
+ if (!tx_queue->buffer)
+ return;
+
+ /* Free any buffers left in the ring */
+ while (tx_queue->read_count != tx_queue->write_count) {
+ buffer = &tx_queue->buffer[tx_queue->read_count &
+ tx_queue->efx->type->txd_ring_mask];
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->continuation = 1;
+ buffer->len = 0;
+
+ ++tx_queue->read_count;
+ }
+}
+
+void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
+
+ /* Flush TX queue, remove descriptor ring */
+ falcon_fini_tx(tx_queue);
+
+ efx_release_tx_buffers(tx_queue);
+
+ /* Release queue's stop on port, if any */
+ if (tx_queue->stopped) {
+ tx_queue->stopped = 0;
+ efx_wake_queue(tx_queue->efx);
+ }
+}
+
+void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
+ falcon_remove_tx(tx_queue);
+
+ kfree(tx_queue->buffer);
+ tx_queue->buffer = NULL;
+ tx_queue->used = 0;
+}
+
+
diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h
new file mode 100644
index 00000000000..1526a73b4b5
--- /dev/null
+++ b/drivers/net/sfc/tx.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_TX_H
+#define EFX_TX_H
+
+#include "net_driver.h"
+
+int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
+int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
+
+int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
+void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
+
+#endif /* EFX_TX_H */
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
new file mode 100644
index 00000000000..dca62f19019
--- /dev/null
+++ b/drivers/net/sfc/workarounds.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_WORKAROUNDS_H
+#define EFX_WORKAROUNDS_H
+
+/*
+ * Hardware workarounds.
+ * Bug numbers are from Solarflare's Bugzilla.
+ */
+
+#define EFX_WORKAROUND_ALWAYS(efx) 1
+#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
+
+/* XAUI resets if link not detected */
+#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
+/* SNAP frames have TOBE_DISC set */
+#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
+/* RX PCIe double split performance issue */
+#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
+/* TX pkt parser problem with <= 16 byte TXes */
+#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
+/* XGXS and XAUI reset sequencing in SW */
+#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
+/* Low rate CRC errors require XAUI reset */
+#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
+/* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
+ * or a PCIe error (bug 11028) */
+#define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
+/* Transmit flow control may get disabled */
+#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
+/* Flush events can take a very long time to appear */
+#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
+
+/* Spurious parity errors in TSORT buffers */
+#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
+/* iSCSI parsing errors */
+#define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
+/* RX events go missing */
+#define EFX_WORKAROUND_5676 EFX_WORKAROUND_FALCON_A
+/* RX_RESET on A1 */
+#define EFX_WORKAROUND_6555 EFX_WORKAROUND_FALCON_A
+/* Increase filter depth to avoid RX_RESET */
+#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
+/* Flushes may never complete */
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+/* Leak overlength packets rather than free */
+#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
+
+#endif /* EFX_WORKAROUNDS_H */
diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h
new file mode 100644
index 00000000000..b0d1f225b70
--- /dev/null
+++ b/drivers/net/sfc/xenpack.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_XENPACK_H
+#define EFX_XENPACK_H
+
+/* Exported functions from Xenpack standard PHY control */
+
+#include "mdio_10g.h"
+
+/****************************************************************************/
+/* XENPACK MDIO register extensions */
+#define MDIO_XP_LASI_RX_CTRL (0x9000)
+#define MDIO_XP_LASI_TX_CTRL (0x9001)
+#define MDIO_XP_LASI_CTRL (0x9002)
+#define MDIO_XP_LASI_RX_STAT (0x9003)
+#define MDIO_XP_LASI_TX_STAT (0x9004)
+#define MDIO_XP_LASI_STAT (0x9005)
+
+/* Control/Status bits */
+#define XP_LASI_LS_ALARM (1 << 0)
+#define XP_LASI_TX_ALARM (1 << 1)
+#define XP_LASI_RX_ALARM (1 << 2)
+/* These two are Quake vendor extensions to the standard XENPACK defines */
+#define XP_LASI_LS_INTB (1 << 3)
+#define XP_LASI_TEST (1 << 7)
+
+/* Enable LASI interrupts for PHY */
+static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
+{
+ int reg;
+ int phy_id = efx->mii.phy_id;
+ /* Read to clear LASI status register */
+ reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_STAT);
+
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
+}
+
+/* Read the LASI interrupt status to clear the interrupt. */
+static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
+{
+ /* Read to clear link status alarm */
+ return mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
+}
+
+/* Turn off LASI interrupts */
+static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
+{
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_CTRL, 0);
+}
+
+#endif /* EFX_XENPACK_H */
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
new file mode 100644
index 00000000000..66dd5bf1eaa
--- /dev/null
+++ b/drivers/net/sfc/xfp_phy.c
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+/*
+ * Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
+ * See www.amcc.com for details (search for qt2032)
+ */
+
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include "efx.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "xenpack.h"
+#include "phy.h"
+#include "mac.h"
+
+#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS)
+
+/****************************************************************************/
+/* Quake-specific MDIO registers */
+#define MDIO_QUAKE_LED0_REG (0xD006)
+
+void xfp_set_led(struct efx_nic *p, int led, int mode)
+{
+ int addr = MDIO_QUAKE_LED0_REG + led;
+ mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
+ mode);
+}
+
+#define XFP_MAX_RESET_TIME 500
+#define XFP_RESET_WAIT 10
+
+/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
+ * a complete soft reset.
+ */
+static int xfp_reset_phy(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
+ XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
+ XFP_RESET_WAIT);
+ if (rc < 0)
+ goto fail;
+
+ /* Wait 250ms for the PHY to complete bootup */
+ msleep(250);
+
+ /* Check that all the MMDs we expect are present and responding. We
+ * expect faults on some if the link is down, but not on the PHY XS */
+ rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
+ MDIO_MMDREG_DEVS0_PHYXS);
+ if (rc < 0)
+ goto fail;
+
+ efx->board_info.init_leds(efx);
+
+ return rc;
+
+ fail:
+ EFX_ERR(efx, "XFP: reset timed out!\n");
+ return rc;
+}
+
+static int xfp_phy_init(struct efx_nic *efx)
+{
+ u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
+ int rc;
+
+ EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
+ " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
+ MDIO_ID_REV(devid));
+
+ rc = xfp_reset_phy(efx);
+
+ EFX_INFO(efx, "XFP: PHY init %s.\n",
+ rc ? "failed" : "successful");
+
+ return rc;
+}
+
+static void xfp_phy_clear_interrupt(struct efx_nic *efx)
+{
+ xenpack_clear_lasi_irqs(efx);
+}
+
+static int xfp_link_ok(struct efx_nic *efx)
+{
+ return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
+}
+
+static int xfp_phy_check_hw(struct efx_nic *efx)
+{
+ int rc = 0;
+ int link_up = xfp_link_ok(efx);
+ /* Simulate a PHY event if link state has changed */
+ if (link_up != efx->link_up)
+ falcon_xmac_sim_phy_event(efx);
+
+ return rc;
+}
+
+static void xfp_phy_reconfigure(struct efx_nic *efx)
+{
+ efx->link_up = xfp_link_ok(efx);
+ efx->link_options = GM_LPA_10000FULL;
+}
+
+
+static void xfp_phy_fini(struct efx_nic *efx)
+{
+ /* Clobber the LED if it was blinking */
+ efx->board_info.blink(efx, 0);
+}
+
+struct efx_phy_operations falcon_xfp_phy_ops = {
+ .init = xfp_phy_init,
+ .reconfigure = xfp_phy_reconfigure,
+ .check_hw = xfp_phy_check_hw,
+ .fini = xfp_phy_fini,
+ .clear_interrupt = xfp_phy_clear_interrupt,
+ .reset_xaui = efx_port_dummy_op_void,
+ .mmds = XFP_REQUIRED_DEVS,
+};
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 20745fd4e97..abc63b0663b 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -212,6 +212,12 @@ enum _DescStatusBit {
THOL2 = 0x20000000,
THOL1 = 0x10000000,
THOL0 = 0x00000000,
+
+ WND = 0x00080000,
+ TABRT = 0x00040000,
+ FIFO = 0x00020000,
+ LINK = 0x00010000,
+ ColCountMask = 0x0000ffff,
/* RxDesc.status */
IPON = 0x20000000,
TCPON = 0x10000000,
@@ -480,30 +486,23 @@ static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
desc->status = 0x0;
}
-static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
- struct RxDesc *desc, u32 rx_buf_sz)
+static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
+ struct RxDesc *desc)
{
+ u32 rx_buf_sz = tp->rx_buf_sz;
struct sk_buff *skb;
- dma_addr_t mapping;
- int ret = 0;
-
- skb = dev_alloc_skb(rx_buf_sz);
- if (!skb)
- goto err_out;
-
- *sk_buff = skb;
- mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
+ if (likely(skb)) {
+ dma_addr_t mapping;
- sis190_map_to_asic(desc, mapping, rx_buf_sz);
-out:
- return ret;
+ mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ sis190_map_to_asic(desc, mapping, rx_buf_sz);
+ } else
+ sis190_make_unusable_by_asic(desc);
-err_out:
- ret = -ENOMEM;
- sis190_make_unusable_by_asic(desc);
- goto out;
+ return skb;
}
static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
@@ -512,37 +511,41 @@ static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
u32 cur;
for (cur = start; cur < end; cur++) {
- int ret, i = cur % NUM_RX_DESC;
+ unsigned int i = cur % NUM_RX_DESC;
if (tp->Rx_skbuff[i])
continue;
- ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
- tp->RxDescRing + i, tp->rx_buf_sz);
- if (ret < 0)
+ tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i);
+
+ if (!tp->Rx_skbuff[i])
break;
}
return cur - start;
}
-static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
- struct RxDesc *desc, int rx_buf_sz)
+static bool sis190_try_rx_copy(struct sis190_private *tp,
+ struct sk_buff **sk_buff, int pkt_size,
+ dma_addr_t addr)
{
- int ret = -1;
+ struct sk_buff *skb;
+ bool done = false;
- if (pkt_size < rx_copybreak) {
- struct sk_buff *skb;
+ if (pkt_size >= rx_copybreak)
+ goto out;
- skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
- if (skb) {
- skb_reserve(skb, NET_IP_ALIGN);
- skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
- *sk_buff = skb;
- sis190_give_to_asic(desc, rx_buf_sz);
- ret = 0;
- }
- }
- return ret;
+ skb = netdev_alloc_skb(tp->dev, pkt_size + 2);
+ if (!skb)
+ goto out;
+
+ pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size,
+ PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, 2);
+ skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
+ *sk_buff = skb;
+ done = true;
+out:
+ return done;
}
static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
@@ -592,9 +595,9 @@ static int sis190_rx_interrupt(struct net_device *dev,
sis190_give_to_asic(desc, tp->rx_buf_sz);
else {
struct sk_buff *skb = tp->Rx_skbuff[entry];
+ dma_addr_t addr = le32_to_cpu(desc->addr);
int pkt_size = (status & RxSizeMask) - 4;
- void (*pci_action)(struct pci_dev *, dma_addr_t,
- size_t, int) = pci_dma_sync_single_for_device;
+ struct pci_dev *pdev = tp->pci_dev;
if (unlikely(pkt_size > tp->rx_buf_sz)) {
net_intr(tp, KERN_INFO
@@ -606,20 +609,18 @@ static int sis190_rx_interrupt(struct net_device *dev,
continue;
}
- pci_dma_sync_single_for_cpu(tp->pci_dev,
- le32_to_cpu(desc->addr), tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
- if (sis190_try_rx_copy(&skb, pkt_size, desc,
- tp->rx_buf_sz)) {
- pci_action = pci_unmap_single;
+ if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) {
+ pci_dma_sync_single_for_device(pdev, addr,
+ tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ sis190_give_to_asic(desc, tp->rx_buf_sz);
+ } else {
+ pci_unmap_single(pdev, addr, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
tp->Rx_skbuff[entry] = NULL;
sis190_make_unusable_by_asic(desc);
}
- pci_action(tp->pci_dev, le32_to_cpu(desc->addr),
- tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
@@ -658,9 +659,31 @@ static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
memset(desc, 0x00, sizeof(*desc));
}
+static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats)
+{
+#define TxErrMask (WND | TABRT | FIFO | LINK)
+
+ if (!unlikely(status & TxErrMask))
+ return 0;
+
+ if (status & WND)
+ stats->tx_window_errors++;
+ if (status & TABRT)
+ stats->tx_aborted_errors++;
+ if (status & FIFO)
+ stats->tx_fifo_errors++;
+ if (status & LINK)
+ stats->tx_carrier_errors++;
+
+ stats->tx_errors++;
+
+ return -1;
+}
+
static void sis190_tx_interrupt(struct net_device *dev,
struct sis190_private *tp, void __iomem *ioaddr)
{
+ struct net_device_stats *stats = &dev->stats;
u32 pending, dirty_tx = tp->dirty_tx;
/*
* It would not be needed if queueing was allowed to be enabled
@@ -675,15 +698,19 @@ static void sis190_tx_interrupt(struct net_device *dev,
for (; pending; pending--, dirty_tx++) {
unsigned int entry = dirty_tx % NUM_TX_DESC;
struct TxDesc *txd = tp->TxDescRing + entry;
+ u32 status = le32_to_cpu(txd->status);
struct sk_buff *skb;
- if (le32_to_cpu(txd->status) & OWNbit)
+ if (status & OWNbit)
break;
skb = tp->Tx_skbuff[entry];
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
+ if (likely(sis190_tx_pkt_err(status, stats) == 0)) {
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+ stats->collisions += ((status & ColCountMask) - 1);
+ }
sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
tp->Tx_skbuff[entry] = NULL;
@@ -904,10 +931,9 @@ static void sis190_phy_task(struct work_struct *work)
mod_timer(&tp->timer, jiffies + HZ/10);
} else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
BMSR_ANEGCOMPLETE)) {
- net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n",
- dev->name);
netif_carrier_off(dev);
- mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
+ net_link(tp, KERN_WARNING "%s: auto-negotiating...\n",
+ dev->name);
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
} else {
/* Rejoice ! */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5a55ede352f..84af68fdb6c 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -396,14 +396,14 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
/* Order of next two lines is *very* important.
* When we are sending a little amount of data,
- * the transfer may be completed inside driver.write()
+ * the transfer may be completed inside the ops->write()
* routine, because it's running with interrupts enabled.
* In this case we *never* got WRITE_WAKEUP event,
* if we did not request it before write operation.
* 14 Oct 1994 Dmitry Gorodchanin.
*/
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
#ifdef SL_CHECK_TRANSMIT
sl->dev->trans_start = jiffies;
#endif
@@ -437,7 +437,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
return;
}
- actual = tty->driver->write(tty, sl->xhead, sl->xleft);
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
}
@@ -462,7 +462,7 @@ static void sl_tx_timeout(struct net_device *dev)
}
printk(KERN_WARNING "%s: transmit timed out, %s?\n",
dev->name,
- (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+ (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error");
sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@@ -830,6 +830,9 @@ static int slip_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
/* RTnetlink lock is misused here to serialize concurrent
opens of slip channels. There are better ways, but it is
the simplest one.
@@ -1432,7 +1435,7 @@ static void sl_outfill(unsigned long sls)
/* put END into tty queue. Is it right ??? */
if (!netif_queue_stopped(sl->dev)) {
/* if device busy no outfill */
- sl->tty->driver->write(sl->tty, &s, 1);
+ sl->tty->ops->write(sl->tty, &s, 1);
}
} else
set_bit(SLF_OUTWAIT, &sl->flags);
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 63abfd72542..e03eef2f228 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -178,6 +178,20 @@ static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal)
CPC_TTY_UNLOCK(card,flags);
}
+
+static const struct tty_operations pc300_ops = {
+ .open = cpc_tty_open,
+ .close = cpc_tty_close,
+ .write = cpc_tty_write,
+ .write_room = cpc_tty_write_room,
+ .chars_in_buffer = cpc_tty_chars_in_buffer,
+ .tiocmset = pc300_tiocmset,
+ .tiocmget = pc300_tiocmget,
+ .flush_buffer = cpc_tty_flush_buffer,
+ .hangup = cpc_tty_hangup,
+};
+
+
/*
* PC300 TTY initialization routine
*
@@ -225,15 +239,7 @@ void cpc_tty_init(pc300dev_t *pc300dev)
serial_drv.flags = TTY_DRIVER_REAL_RAW;
/* interface routines from the upper tty layer to the tty driver */
- serial_drv.open = cpc_tty_open;
- serial_drv.close = cpc_tty_close;
- serial_drv.write = cpc_tty_write;
- serial_drv.write_room = cpc_tty_write_room;
- serial_drv.chars_in_buffer = cpc_tty_chars_in_buffer;
- serial_drv.tiocmset = pc300_tiocmset;
- serial_drv.tiocmget = pc300_tiocmget;
- serial_drv.flush_buffer = cpc_tty_flush_buffer;
- serial_drv.hangup = cpc_tty_hangup;
+ tty_set_operations(&serial_drv, &pc300_ops);
/* register the TTY driver */
if (tty_register_driver(&serial_drv)) {
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 0f8aca8a4d4..249e18053d5 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -17,7 +17,7 @@
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -95,7 +95,7 @@ static struct x25_asy *x25_asy_alloc(void)
x25_asy_devs[i] = dev;
return sl;
} else {
- printk("x25_asy_alloc() - register_netdev() failure.\n");
+ printk(KERN_WARNING "x25_asy_alloc() - register_netdev() failure.\n");
free_netdev(dev);
}
}
@@ -112,23 +112,22 @@ static void x25_asy_free(struct x25_asy *sl)
kfree(sl->xbuff);
sl->xbuff = NULL;
- if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
- printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
- }
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags))
+ printk(KERN_ERR "%s: x25_asy_free for already free unit.\n",
+ sl->dev->name);
}
static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
{
struct x25_asy *sl = dev->priv;
unsigned char *xbuff, *rbuff;
- int len = 2* newmtu;
+ int len = 2 * newmtu;
xbuff = kmalloc(len + 4, GFP_ATOMIC);
rbuff = kmalloc(len + 4, GFP_ATOMIC);
- if (xbuff == NULL || rbuff == NULL)
- {
- printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
+ if (xbuff == NULL || rbuff == NULL) {
+ printk(KERN_WARNING "%s: unable to grow X.25 buffers, MTU change cancelled.\n",
dev->name);
kfree(xbuff);
kfree(rbuff);
@@ -193,25 +192,23 @@ static void x25_asy_bump(struct x25_asy *sl)
int err;
count = sl->rcount;
- sl->stats.rx_bytes+=count;
-
+ sl->stats.rx_bytes += count;
+
skb = dev_alloc_skb(count+1);
- if (skb == NULL)
- {
- printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n",
+ sl->dev->name);
sl->stats.rx_dropped++;
return;
}
- skb_push(skb,1); /* LAPB internal control */
- memcpy(skb_put(skb,count), sl->rbuff, count);
+ skb_push(skb, 1); /* LAPB internal control */
+ memcpy(skb_put(skb, count), sl->rbuff, count);
skb->protocol = x25_type_trans(skb, sl->dev);
- if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK)
- {
+ err = lapb_data_received(skb->dev, skb);
+ if (err != LAPB_OK) {
kfree_skb(skb);
- printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
- }
- else
- {
+ printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
+ } else {
netif_rx(skb);
sl->dev->last_rx = jiffies;
sl->stats.rx_packets++;
@@ -224,10 +221,11 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
unsigned char *p;
int actual, count, mtu = sl->dev->mtu;
- if (len > mtu)
- { /* Sigh, shouldn't occur BUT ... */
+ if (len > mtu) {
+ /* Sigh, shouldn't occur BUT ... */
len = mtu;
- printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
+ printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n",
+ sl->dev->name);
sl->stats.tx_dropped++;
x25_asy_unlock(sl);
return;
@@ -245,7 +243,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
* 14 Oct 1994 Dmitry Gorodchanin.
*/
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
sl->xleft = count - actual;
sl->xhead = sl->xbuff + actual;
/* VSV */
@@ -265,8 +263,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
- if (sl->xleft <= 0)
- {
+ if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sl->stats.tx_packets++;
@@ -275,14 +272,14 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
return;
}
- actual = tty->driver->write(tty, sl->xhead, sl->xleft);
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
}
static void x25_asy_timeout(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
spin_lock(&sl->lock);
if (netif_queue_stopped(dev)) {
@@ -290,7 +287,7 @@ static void x25_asy_timeout(struct net_device *dev)
* 14 Oct 1994 Dmitry Gorodchanin.
*/
printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+ (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error");
sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@@ -303,31 +300,34 @@ static void x25_asy_timeout(struct net_device *dev)
static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
int err;
if (!netif_running(sl->dev)) {
- printk("%s: xmit call when iface is down\n", dev->name);
+ printk(KERN_ERR "%s: xmit call when iface is down\n",
+ dev->name);
kfree_skb(skb);
return 0;
}
-
- switch(skb->data[0])
- {
- case 0x00:break;
- case 0x01: /* Connection request .. do nothing */
- if((err=lapb_connect_request(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
- kfree_skb(skb);
- return 0;
- case 0x02: /* Disconnect request .. do nothing - hang up ?? */
- if((err=lapb_disconnect_request(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
- default:
- kfree_skb(skb);
- return 0;
+
+ switch (skb->data[0]) {
+ case 0x00:
+ break;
+ case 0x01: /* Connection request .. do nothing */
+ err = lapb_connect_request(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
+ kfree_skb(skb);
+ return 0;
+ case 0x02: /* Disconnect request .. do nothing - hang up ?? */
+ err = lapb_disconnect_request(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
+ default:
+ kfree_skb(skb);
+ return 0;
}
- skb_pull(skb,1); /* Remove control byte */
+ skb_pull(skb, 1); /* Remove control byte */
/*
* If we are busy already- too bad. We ought to be able
* to queue things at this point, to allow for a little
@@ -338,10 +338,10 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* So, no queues !
* 14 Oct 1994 Dmitry Gorodchanin.
*/
-
- if((err=lapb_data_request(dev,skb))!=LAPB_OK)
- {
- printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
+
+ err = lapb_data_request(dev, skb);
+ if (err != LAPB_OK) {
+ printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb);
return 0;
}
@@ -357,7 +357,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* Called when I frame data arrives. We did the work above - throw it
* at the net layer.
*/
-
+
static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
{
skb->dev->last_rx = jiffies;
@@ -369,24 +369,22 @@ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
* busy cases too well. Its tricky to see how to do this nicely -
* perhaps lapb should allow us to bounce this ?
*/
-
+
static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
{
- struct x25_asy *sl=dev->priv;
-
+ struct x25_asy *sl = dev->priv;
+
spin_lock(&sl->lock);
- if (netif_queue_stopped(sl->dev) || sl->tty == NULL)
- {
+ if (netif_queue_stopped(sl->dev) || sl->tty == NULL) {
spin_unlock(&sl->lock);
printk(KERN_ERR "x25_asy: tbusy drop\n");
kfree_skb(skb);
return;
}
/* We were not busy, so we are now... :-) */
- if (skb != NULL)
- {
+ if (skb != NULL) {
x25_asy_lock(sl);
- sl->stats.tx_bytes+=skb->len;
+ sl->stats.tx_bytes += skb->len;
x25_asy_encaps(sl, skb->data, skb->len);
dev_kfree_skb(skb);
}
@@ -396,15 +394,16 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
/*
* LAPB connection establish/down information.
*/
-
+
static void x25_asy_connected(struct net_device *dev, int reason)
{
struct x25_asy *sl = dev->priv;
struct sk_buff *skb;
unsigned char *ptr;
- if ((skb = dev_alloc_skb(1)) == NULL) {
- printk(KERN_ERR "lapbeth: out of memory\n");
+ skb = dev_alloc_skb(1);
+ if (skb == NULL) {
+ printk(KERN_ERR "x25_asy: out of memory\n");
return;
}
@@ -422,7 +421,8 @@ static void x25_asy_disconnected(struct net_device *dev, int reason)
struct sk_buff *skb;
unsigned char *ptr;
- if ((skb = dev_alloc_skb(1)) == NULL) {
+ skb = dev_alloc_skb(1);
+ if (skb == NULL) {
printk(KERN_ERR "x25_asy: out of memory\n");
return;
}
@@ -449,7 +449,7 @@ static struct lapb_register_struct x25_asy_callbacks = {
/* Open the low-level part of the X.25 channel. Easy! */
static int x25_asy_open(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
unsigned long len;
int err;
@@ -466,13 +466,11 @@ static int x25_asy_open(struct net_device *dev)
len = dev->mtu * 2;
sl->rbuff = kmalloc(len + 4, GFP_KERNEL);
- if (sl->rbuff == NULL) {
+ if (sl->rbuff == NULL)
goto norbuff;
- }
sl->xbuff = kmalloc(len + 4, GFP_KERNEL);
- if (sl->xbuff == NULL) {
+ if (sl->xbuff == NULL)
goto noxbuff;
- }
sl->buffsize = len;
sl->rcount = 0;
@@ -480,11 +478,12 @@ static int x25_asy_open(struct net_device *dev)
sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
netif_start_queue(dev);
-
+
/*
* Now attach LAPB
*/
- if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK)
+ err = lapb_register(dev, &x25_asy_callbacks);
+ if (err == LAPB_OK)
return 0;
/* Cleanup */
@@ -499,18 +498,20 @@ norbuff:
/* Close the low-level part of the X.25 channel. Easy! */
static int x25_asy_close(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
int err;
spin_lock(&sl->lock);
- if (sl->tty)
+ if (sl->tty)
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
netif_stop_queue(dev);
sl->rcount = 0;
sl->xleft = 0;
- if((err=lapb_unregister(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
+ err = lapb_unregister(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
+ err);
spin_unlock(&sl->lock);
return 0;
}
@@ -521,8 +522,9 @@ static int x25_asy_close(struct net_device *dev)
* a block of X.25 data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
-
-static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+
+static void x25_asy_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
@@ -533,9 +535,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->stats.rx_errors++;
- }
cp++;
continue;
}
@@ -556,31 +557,31 @@ static int x25_asy_open_tty(struct tty_struct *tty)
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
/* First make sure we're not already connected. */
- if (sl && sl->magic == X25_ASY_MAGIC) {
+ if (sl && sl->magic == X25_ASY_MAGIC)
return -EEXIST;
- }
/* OK. Find a free X.25 channel to use. */
- if ((sl = x25_asy_alloc()) == NULL) {
+ sl = x25_asy_alloc();
+ if (sl == NULL)
return -ENFILE;
- }
sl->tty = tty;
tty->disc_data = sl;
tty->receive_room = 65536;
- if (tty->driver->flush_buffer) {
- tty->driver->flush_buffer(tty);
- }
+ tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
/* Restore default settings */
sl->dev->type = ARPHRD_X25;
-
+
/* Perform the low-level X.25 async init */
- if ((err = x25_asy_open(sl->dev)))
+ err = x25_asy_open(sl->dev);
+ if (err)
return err;
-
/* Done. We have linked the TTY line to a channel. */
return sl->dev->base_addr;
}
@@ -601,9 +602,7 @@ static void x25_asy_close_tty(struct tty_struct *tty)
return;
if (sl->dev->flags & IFF_UP)
- {
- (void) dev_close(sl->dev);
- }
+ dev_close(sl->dev);
tty->disc_data = NULL;
sl->tty = NULL;
@@ -613,8 +612,7 @@ static void x25_asy_close_tty(struct tty_struct *tty)
static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-
+ struct x25_asy *sl = dev->priv;
return &sl->stats;
}
@@ -641,21 +639,19 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
* character sequence, according to the X.25 protocol.
*/
- while (len-- > 0)
- {
- switch(c = *s++)
- {
- case X25_END:
- *ptr++ = X25_ESC;
- *ptr++ = X25_ESCAPE(X25_END);
- break;
- case X25_ESC:
- *ptr++ = X25_ESC;
- *ptr++ = X25_ESCAPE(X25_ESC);
- break;
- default:
- *ptr++ = c;
- break;
+ while (len-- > 0) {
+ switch (c = *s++) {
+ case X25_END:
+ *ptr++ = X25_ESC;
+ *ptr++ = X25_ESCAPE(X25_END);
+ break;
+ case X25_ESC:
+ *ptr++ = X25_ESC;
+ *ptr++ = X25_ESCAPE(X25_ESC);
+ break;
+ default:
+ *ptr++ = c;
+ break;
}
}
*ptr++ = X25_END;
@@ -665,31 +661,25 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
{
- switch(s)
- {
- case X25_END:
- if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
- {
- x25_asy_bump(sl);
- }
- clear_bit(SLF_ESCAPE, &sl->flags);
- sl->rcount = 0;
- return;
-
- case X25_ESC:
- set_bit(SLF_ESCAPE, &sl->flags);
- return;
-
- case X25_ESCAPE(X25_ESC):
- case X25_ESCAPE(X25_END):
- if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
- s = X25_UNESCAPE(s);
- break;
- }
- if (!test_bit(SLF_ERROR, &sl->flags))
- {
- if (sl->rcount < sl->buffsize)
- {
+ switch (s) {
+ case X25_END:
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
+ && sl->rcount > 2)
+ x25_asy_bump(sl);
+ clear_bit(SLF_ESCAPE, &sl->flags);
+ sl->rcount = 0;
+ return;
+ case X25_ESC:
+ set_bit(SLF_ESCAPE, &sl->flags);
+ return;
+ case X25_ESCAPE(X25_ESC):
+ case X25_ESCAPE(X25_END):
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
+ s = X25_UNESCAPE(s);
+ break;
+ }
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < sl->buffsize) {
sl->rbuff[sl->rcount++] = s;
return;
}
@@ -709,7 +699,7 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
if (!sl || sl->magic != X25_ASY_MAGIC)
return -EINVAL;
- switch(cmd) {
+ switch (cmd) {
case SIOCGIFNAME:
if (copy_to_user((void __user *)arg, sl->dev->name,
strlen(sl->dev->name) + 1))
@@ -724,8 +714,8 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
static int x25_asy_open_dev(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
- if(sl->tty==NULL)
+ struct x25_asy *sl = dev->priv;
+ if (sl->tty == NULL)
return -ENODEV;
return 0;
}
@@ -741,9 +731,9 @@ static void x25_asy_setup(struct net_device *dev)
set_bit(SLF_INUSE, &sl->flags);
/*
- * Finish setting up the DEVICE info.
+ * Finish setting up the DEVICE info.
*/
-
+
dev->mtu = SL_MTU;
dev->hard_start_xmit = x25_asy_xmit;
dev->tx_timeout = x25_asy_timeout;
@@ -778,9 +768,10 @@ static int __init init_x25_asy(void)
x25_asy_maxdev = 4; /* Sanity */
printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
- "(dynamic channels, max=%d).\n", x25_asy_maxdev );
+ "(dynamic channels, max=%d).\n", x25_asy_maxdev);
- x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL);
+ x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device *),
+ GFP_KERNEL);
if (!x25_asy_devs) {
printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
"array! Uaargh! (-> No X.25 available)\n");
@@ -802,7 +793,7 @@ static void __exit exit_x25_asy(void)
struct x25_asy *sl = dev->priv;
spin_lock_bh(&sl->lock);
- if (sl->tty)
+ if (sl->tty)
tty_hangup(sl->tty);
spin_unlock_bh(&sl->lock);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 9a25f550fd1..d5b7a76fcaa 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -6,6 +6,10 @@ config IWLCORE
tristate "Intel Wireless Wifi Core"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select IWLWIFI
+ select MAC80211_LEDS if IWLWIFI_LEDS
+ select LEDS_CLASS if IWLWIFI_LEDS
+ select RFKILL if IWLWIFI_RFKILL
+ select RFKILL_INPUT if IWLWIFI_RFKILL
config IWLWIFI_LEDS
bool
@@ -14,8 +18,6 @@ config IWLWIFI_LEDS
config IWLWIFI_RFKILL
boolean "IWLWIFI RF kill support"
depends on IWLCORE
- select RFKILL
- select RFKILL_INPUT
config IWL4965
tristate "Intel Wireless WiFi 4965AGN"
@@ -55,8 +57,6 @@ config IWL4965_HT
config IWL4965_LEDS
bool "Enable LEDS features in iwl4965 driver"
depends on IWL4965
- select MAC80211_LEDS
- select LEDS_CLASS
select IWLWIFI_LEDS
---help---
This option enables LEDS for the iwlwifi drivers
@@ -112,6 +112,8 @@ config IWL3945
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
select IWLWIFI
+ select MAC80211_LEDS if IWL3945_LEDS
+ select LEDS_CLASS if IWL3945_LEDS
---help---
Select to build the driver supporting the:
@@ -143,8 +145,6 @@ config IWL3945_SPECTRUM_MEASUREMENT
config IWL3945_LEDS
bool "Enable LEDS features in iwl3945 driver"
depends on IWL3945
- select MAC80211_LEDS
- select LEDS_CLASS
---help---
This option enables LEDS for the iwl3945 driver.
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index bced3fe1cf8..5dd23c93497 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -768,41 +768,17 @@ static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst,
/* General routines for STRIP */
/*
- * get_baud returns the current baud rate, as one of the constants defined in
- * termbits.h
- * If the user has issued a baud rate override using the 'setserial' command
- * and the logical current rate is set to 38.4, then the true baud rate
- * currently in effect (57.6 or 115.2) is returned.
- */
-static unsigned int get_baud(struct tty_struct *tty)
-{
- if (!tty || !tty->termios)
- return (0);
- if ((tty->termios->c_cflag & CBAUD) == B38400 && tty->driver_data) {
- struct async_struct *info =
- (struct async_struct *) tty->driver_data;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- return (B57600);
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- return (B115200);
- }
- return (tty->termios->c_cflag & CBAUD);
-}
-
-/*
* set_baud sets the baud rate to the rate defined by baudcode
- * Note: The rate B38400 should be avoided, because the user may have
- * issued a 'setserial' speed override to map that to a different speed.
- * We could achieve a true rate of 38400 if we needed to by cancelling
- * any user speed override that is in place, but that might annoy the
- * user, so it is simplest to just avoid using 38400.
*/
-static void set_baud(struct tty_struct *tty, unsigned int baudcode)
+static void set_baud(struct tty_struct *tty, speed_t baudrate)
{
- struct ktermios old_termios = *(tty->termios);
- tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */
- tty->termios->c_cflag |= baudcode; /* Set the new baud setting */
- tty->driver->set_termios(tty, &old_termios);
+ struct ktermios old_termios;
+
+ mutex_lock(&tty->termios_mutex);
+ old_termios =*(tty->termios);
+ tty_encode_baud_rate(tty, baudrate, baudrate);
+ tty->ops->set_termios(tty, &old_termios);
+ mutex_unlock(&tty->termios_mutex);
}
/*
@@ -1217,7 +1193,7 @@ static void ResetRadio(struct strip *strip_info)
strip_info->watchdog_doreset = jiffies + 1 * HZ;
/* If the user has selected a baud rate above 38.4 see what magic we have to do */
- if (strip_info->user_baud > B38400) {
+ if (strip_info->user_baud > 38400) {
/*
* Subtle stuff: Pay attention :-)
* If the serial port is currently at the user's selected (>38.4) rate,
@@ -1227,17 +1203,17 @@ static void ResetRadio(struct strip *strip_info)
* issued the ATS304 command last time through, so this time we restore
* the user's selected rate and issue the normal starmode reset string.
*/
- if (strip_info->user_baud == get_baud(tty)) {
+ if (strip_info->user_baud == tty_get_baud_rate(tty)) {
static const char b0[] = "ate0q1s304=57600\r";
static const char b1[] = "ate0q1s304=115200\r";
static const StringDescriptor baudstring[2] =
{ {b0, sizeof(b0) - 1}
, {b1, sizeof(b1) - 1}
};
- set_baud(tty, B19200);
- if (strip_info->user_baud == B57600)
+ set_baud(tty, 19200);
+ if (strip_info->user_baud == 57600)
s = baudstring[0];
- else if (strip_info->user_baud == B115200)
+ else if (strip_info->user_baud == 115200)
s = baudstring[1];
else
s = baudstring[1]; /* For now */
@@ -1245,7 +1221,7 @@ static void ResetRadio(struct strip *strip_info)
set_baud(tty, strip_info->user_baud);
}
- tty->driver->write(tty, s.string, s.length);
+ tty->ops->write(tty, s.string, s.length);
#ifdef EXT_COUNTERS
strip_info->tx_ebytes += s.length;
#endif
@@ -1267,7 +1243,7 @@ static void strip_write_some_more(struct tty_struct *tty)
if (strip_info->tx_left > 0) {
int num_written =
- tty->driver->write(tty, strip_info->tx_head,
+ tty->ops->write(tty, strip_info->tx_head,
strip_info->tx_left);
strip_info->tx_left -= num_written;
strip_info->tx_head += num_written;
@@ -2457,7 +2433,7 @@ static int strip_open_low(struct net_device *dev)
strip_info->working = FALSE;
strip_info->firmware_level = NoStructure;
strip_info->next_command = CompatibilityCommand;
- strip_info->user_baud = get_baud(strip_info->tty);
+ strip_info->user_baud = tty_get_baud_rate(strip_info->tty);
printk(KERN_INFO "%s: Initializing Radio.\n",
strip_info->dev->name);
@@ -2632,6 +2608,13 @@ static int strip_open(struct tty_struct *tty)
return -EEXIST;
/*
+ * We need a write method.
+ */
+
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
+ /*
* OK. Find a free STRIP channel to use.
*/
if ((strip_info = strip_alloc()) == NULL)
@@ -2652,8 +2635,7 @@ static int strip_open(struct tty_struct *tty)
tty->disc_data = strip_info;
tty->receive_room = 65536;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/*
* Restore default settings
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 54a6ef72906..0338b091267 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -76,7 +76,7 @@ int parport_wait_event (struct parport *port, signed long timeout)
semaphore. */
return 1;
- init_timer (&timer);
+ init_timer_on_stack(&timer);
timer.expires = jiffies + timeout;
timer.function = timeout_waiting_on_port;
port_from_cookie[port->number % PARPORT_MAX] = port;
@@ -88,6 +88,8 @@ int parport_wait_event (struct parport *port, signed long timeout)
/* Timed out. */
ret = 1;
+ destroy_timer_on_stack(&timer);
+
return ret;
}
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 0e77ae2b71a..e6a7e847ee8 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -365,11 +365,11 @@ static int __devinit parport_init_chip(struct parisc_device *dev)
if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) {
/* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */
- printk("%s: initialize bidirectional-mode.\n", __FUNCTION__);
+ printk("%s: initialize bidirectional-mode.\n", __func__);
parport_writeb ( (0x10 + 0x20), port + 4);
} else {
- printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__);
+ printk("%s: enhanced parport-modes not supported.\n", __func__);
}
p = parport_gsc_probe_port(port, 0, dev->irq,
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index e71092e8028..e0c2a4584ec 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1415,7 +1415,7 @@ static void __devinit winbond_check(int io, int key)
{
int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without key */
@@ -1449,7 +1449,7 @@ static void __devinit winbond_check2(int io,int key)
{
int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without the key */
@@ -1482,7 +1482,7 @@ static void __devinit smsc_check(int io, int key)
{
int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without the key */
@@ -1547,7 +1547,7 @@ static void __devinit detect_and_report_it87(void)
u8 r;
if (verbose_probing)
printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
- if (!request_region(0x2e, 1, __FUNCTION__))
+ if (!request_region(0x2e, 1, __func__))
return;
outb(0x87, 0x2e);
outb(0x01, 0x2e);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 0e1f35c9ed9..3e5653c92f4 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -982,15 +982,16 @@ tty3215_write(struct tty_struct * tty,
/*
* Put character routine for 3215 ttys
*/
-static void
+static int
tty3215_put_char(struct tty_struct *tty, unsigned char ch)
{
struct raw3215_info *raw;
if (!tty)
- return;
+ return 0;
raw = (struct raw3215_info *) tty->driver_data;
raw3215_putchar(raw, ch);
+ return 1;
}
static void
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index b8f35bc52b7..9e784d5f7f5 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -10,6 +10,7 @@
#include <linux/cpu.h>
#include <linux/sysdev.h>
#include <linux/workqueue.h>
+#include <asm/smp.h>
#include "sclp.h"
#define TAG "sclp_config: "
@@ -19,9 +20,11 @@ struct conf_mgm_data {
u8 ev_qualifier;
} __attribute__((packed));
+#define EV_QUAL_CPU_CHANGE 1
#define EV_QUAL_CAP_CHANGE 3
static struct work_struct sclp_cpu_capability_work;
+static struct work_struct sclp_cpu_change_work;
static void sclp_cpu_capability_notify(struct work_struct *work)
{
@@ -37,13 +40,24 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
put_online_cpus();
}
+static void sclp_cpu_change_notify(struct work_struct *work)
+{
+ smp_rescan_cpus();
+}
+
static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
{
struct conf_mgm_data *cdata;
cdata = (struct conf_mgm_data *)(evbuf + 1);
- if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE)
+ switch (cdata->ev_qualifier) {
+ case EV_QUAL_CPU_CHANGE:
+ schedule_work(&sclp_cpu_change_work);
+ break;
+ case EV_QUAL_CAP_CHANGE:
schedule_work(&sclp_cpu_capability_work);
+ break;
+ }
}
static struct sclp_register sclp_conf_register =
@@ -57,6 +71,7 @@ static int __init sclp_conf_init(void)
int rc;
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
+ INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
rc = sclp_register(&sclp_conf_register);
if (rc) {
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index e3b3d390b4a..40b11521cd2 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -412,14 +412,14 @@ sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
* - including previous characters from sclp_tty_put_char() and strings from
* sclp_write() without final '\n' - will be written.
*/
-static void
+static int
sclp_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
sclp_tty_chars[sclp_tty_chars_count++] = ch;
if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
- }
+ } return 1;
}
/*
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index ed507594e62..35707c04e61 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -524,11 +524,15 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp)
* NOTE: include/linux/tty_driver.h specifies that a character should be
* ignored if there is no room in the queue. This driver implements a different
* semantic in that it will block when there is no more room left.
+ *
+ * FIXME: putchar can currently be called from BH and other non blocking
+ * handlers so this semantic isn't a good idea.
*/
-static void
+static int
sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
{
__sclp_vt220_write(&ch, 1, 0, 0, 1);
+ return 1;
}
/*
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 70b1980a08b..c1f2adefad4 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -965,7 +965,7 @@ tty3270_write_room(struct tty_struct *tty)
* Insert character into the screen at the current position with the
* current color and highlight. This function does NOT do cursor movement.
*/
-static void
+static int
tty3270_put_character(struct tty3270 *tp, char ch)
{
struct tty3270_line *line;
@@ -986,6 +986,7 @@ tty3270_put_character(struct tty3270 *tp, char ch)
cell->character = tp->view.ascebc[(unsigned int) ch];
cell->highlight = tp->highlight;
cell->f_color = tp->f_color;
+ return 1;
}
/*
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index fe1ad172215..26a930e832b 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -152,44 +152,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
+static int __get_next_bus_id(const char **buf, char *bus_id)
+{
+ int rc, len;
+ char *start, *end;
+
+ start = (char *)*buf;
+ end = strchr(start, ',');
+ if (!end) {
+ /* Last entry. Strip trailing newline, if applicable. */
+ end = strchr(start, '\n');
+ if (end)
+ *end = '\0';
+ len = strlen(start) + 1;
+ } else {
+ len = end - start + 1;
+ end++;
+ }
+ if (len < BUS_ID_SIZE) {
+ strlcpy(bus_id, start, len);
+ rc = 0;
+ } else
+ rc = -EINVAL;
+ *buf = end;
+ return rc;
+}
+
+static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
+{
+ int cssid, ssid, devno;
+
+ /* Must be of form %x.%x.%04x */
+ if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
+ return 0;
+ return 1;
+}
+
/**
- * ccwgroup_create() - create and register a ccw group device
+ * ccwgroup_create_from_string() - create and register a ccw group device
* @root: parent device for the new device
* @creator_id: identifier of creating driver
* @cdrv: ccw driver of slave devices
- * @argc: number of slave devices
- * @argv: bus ids of slave devices
+ * @num_devices: number of slave devices
+ * @buf: buffer containing comma separated bus ids of slave devices
*
* Create and register a new ccw group device as a child of @root. Slave
- * devices are obtained from the list of bus ids given in @argv[] and must all
+ * devices are obtained from the list of bus ids given in @buf and must all
* belong to @cdrv.
* Returns:
* %0 on success and an error code on failure.
* Context:
* non-atomic
*/
-int ccwgroup_create(struct device *root, unsigned int creator_id,
- struct ccw_driver *cdrv, int argc, char *argv[])
+int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int num_devices,
+ const char *buf)
{
struct ccwgroup_device *gdev;
- int i;
- int rc;
+ int rc, i;
+ char tmp_bus_id[BUS_ID_SIZE];
+ const char *curr_buf;
- if (argc > 256) /* disallow dumb users */
- return -EINVAL;
-
- gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
+ gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
+ GFP_KERNEL);
if (!gdev)
return -ENOMEM;
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
- for (i = 0; i < argc; i++) {
- gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
-
- /* all devices have to be of the same type in
- * order to be grouped */
+ curr_buf = buf;
+ for (i = 0; i < num_devices && curr_buf; i++) {
+ rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
+ if (rc != 0)
+ goto error;
+ if (!__is_valid_bus_id(tmp_bus_id)) {
+ rc = -EINVAL;
+ goto error;
+ }
+ gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
+ /*
+ * All devices have to be of the same type in
+ * order to be grouped.
+ */
if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
@@ -203,9 +248,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
}
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
}
-
+ /* Check for sufficient number of bus ids. */
+ if (i < num_devices && !curr_buf) {
+ rc = -EINVAL;
+ goto error;
+ }
+ /* Check for trailing stuff. */
+ if (i == num_devices && strlen(curr_buf) > 0) {
+ rc = -EINVAL;
+ goto error;
+ }
gdev->creator_id = creator_id;
- gdev->count = argc;
+ gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = root;
gdev->dev.release = ccwgroup_release;
@@ -233,7 +287,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error:
- for (i = 0; i < argc; i++)
+ for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) {
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@@ -243,6 +297,7 @@ error:
put_device(&gdev->dev);
return rc;
}
+EXPORT_SYMBOL(ccwgroup_create_from_string);
static int __init
init_ccwgroup (void)
@@ -318,7 +373,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
{
struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
- unsigned int value;
+ unsigned long value;
int ret;
gdev = to_ccwgroupdev(dev);
@@ -329,7 +384,9 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
if (!try_module_get(gdrv->owner))
return -EINVAL;
- value = simple_strtoul(buf, NULL, 0);
+ ret = strict_strtoul(buf, 0, &value);
+ if (ret)
+ goto out;
ret = count;
if (value == 1)
ccwgroup_set_online(gdev);
@@ -337,6 +394,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
ccwgroup_set_offline(gdev);
else
ret = -EINVAL;
+out:
module_put(gdrv->owner);
return ret;
}
@@ -518,6 +576,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister);
-EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 23ffcc4768a..08a57816130 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -407,8 +407,7 @@ cio_modify (struct subchannel *sch)
/*
* Enable subchannel.
*/
-int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
- u32 intparm)
+int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
char dbf_txt[15];
int ccode;
@@ -426,7 +425,7 @@ int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
for (retry = 5, ret = 0; retry > 0; retry--) {
sch->schib.pmcw.ena = 1;
- sch->schib.pmcw.isc = isc;
+ sch->schib.pmcw.isc = sch->isc;
sch->schib.pmcw.intparm = intparm;
ret = cio_modify(sch);
if (ret == -ENODEV)
@@ -600,6 +599,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
else
sch->opm = chp_get_sch_opm(sch);
sch->lpm = sch->schib.pmcw.pam & sch->opm;
+ sch->isc = 3;
CIO_DEBUG(KERN_INFO, 0,
"Detected device %04x on subchannel 0.%x.%04X"
@@ -610,13 +610,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
/*
* We now have to initially ...
- * ... set "interruption subclass"
* ... enable "concurrent sense"
* ... enable "multipath mode" if more than one
* CHPID is available. This is done regardless
* whether multiple paths are available for us.
*/
- sch->schib.pmcw.isc = 3; /* could be smth. else */
sch->schib.pmcw.csense = 1; /* concurrent sense */
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
@@ -812,6 +810,7 @@ cio_probe_console(void)
* enable console I/O-interrupt subclass 7
*/
ctl_set_bit(6, 24);
+ console_subchannel.isc = 7;
console_subchannel.schib.pmcw.isc = 7;
console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 08f2235c5a6..3c75412904d 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -74,6 +74,7 @@ struct subchannel {
__u8 lpm; /* logical path mask */
__u8 opm; /* operational path mask */
struct schib schib; /* subchannel information block */
+ int isc; /* desired interruption subclass */
struct chsc_ssd_info ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
struct css_driver *driver;
@@ -85,7 +86,7 @@ struct subchannel {
#define to_subchannel(n) container_of(n, struct subchannel, dev)
extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
-extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
+extern int cio_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
extern int cio_clear (struct subchannel *);
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index f4c132ab39e..2808b6833b9 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1219,16 +1219,21 @@ static ssize_t cmb_enable_store(struct device *dev,
{
struct ccw_device *cdev;
int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 16, &val);
+ if (ret)
+ return ret;
cdev = to_ccwdev(dev);
- switch (buf[0]) {
- case '0':
+ switch (val) {
+ case 0:
ret = disable_cmf(cdev);
if (ret)
dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
break;
- case '1':
+ case 1:
ret = enable_cmf(cdev);
if (ret && ret != -EBUSY)
dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index c1afab5f72d..595e327d2f7 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -705,13 +705,17 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
{
struct channel_subsystem *css = to_css(dev);
int ret;
+ unsigned long val;
+ ret = strict_strtoul(buf, 16, &val);
+ if (ret)
+ return ret;
mutex_lock(&css->mutex);
- switch (buf[0]) {
- case '0':
+ switch (val) {
+ case 0:
ret = css->cm_enabled ? chsc_secm(css, 0) : 0;
break;
- case '1':
+ case 1:
ret = css->cm_enabled ? 0 : chsc_secm(css, 1);
break;
default:
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e0c7adb8958..abfd601d237 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -512,8 +512,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ccw_device *cdev = to_ccwdev(dev);
- int i, force;
- char *tmp;
+ int force, ret;
+ unsigned long i;
if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
return -EAGAIN;
@@ -525,25 +525,30 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
if (!strncmp(buf, "force\n", count)) {
force = 1;
i = 1;
+ ret = 0;
} else {
force = 0;
- i = simple_strtoul(buf, &tmp, 16);
+ ret = strict_strtoul(buf, 16, &i);
}
-
+ if (ret)
+ goto out;
switch (i) {
case 0:
online_store_handle_offline(cdev);
+ ret = count;
break;
case 1:
online_store_handle_online(cdev, force);
+ ret = count;
break;
default:
- count = -EINVAL;
+ ret = -EINVAL;
}
+out:
if (cdev->drv)
module_put(cdev->drv->owner);
atomic_set(&cdev->private->onoff, 0);
- return count;
+ return ret;
}
static ssize_t
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 4b92c84fb43..99403b0a97a 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -555,8 +555,7 @@ ccw_device_recognition(struct ccw_device *cdev)
(cdev->private->state != DEV_STATE_BOXED))
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
- ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return ret;
@@ -667,8 +666,7 @@ ccw_device_online(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
if (css_init_done && !get_device(&cdev->dev))
return -ENODEV;
- ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret != 0) {
/* Couldn't enable the subchannel for i/o. Sick device. */
if (ret == -ENODEV)
@@ -1048,8 +1046,7 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
- if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch) != 0)
+ if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return;
@@ -1082,7 +1079,6 @@ device_trigger_reprobe(struct subchannel *sch)
*/
sch->lpm = sch->schib.pmcw.pam & sch->opm;
/* Re-set some bits in the pmcw that were lost. */
- sch->schib.pmcw.isc = 3;
sch->schib.pmcw.csense = 1;
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index a1718a0aa53..f308ad55a6d 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -508,7 +508,7 @@ ccw_device_stlck(struct ccw_device *cdev)
return -ENOMEM;
}
spin_lock_irqsave(sch->lock, flags);
- ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret)
goto out_unlock;
/*
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 43876e28737..445cf364e46 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -3663,11 +3663,11 @@ qdio_performance_stats_show(struct bus_type *bus, char *buf)
static ssize_t
qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
{
- char *tmp;
- int i;
+ unsigned long i;
+ int ret;
- i = simple_strtoul(buf, &tmp, 16);
- if ((i == 0) || (i == 1)) {
+ ret = strict_strtoul(buf, 16, &i);
+ if (!ret && ((i == 0) || (i == 1))) {
if (i == qdio_performance_stats)
return count;
qdio_performance_stats = i;
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index bbef3764fbf..47a7e6200b2 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -17,6 +17,7 @@
#include <linux/virtio_config.h>
#include <linux/interrupt.h>
#include <linux/virtio_ring.h>
+#include <linux/pfn.h>
#include <asm/io.h>
#include <asm/kvm_para.h>
#include <asm/kvm_virtio.h>
@@ -180,11 +181,10 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
config = kvm_vq_config(kdev->desc)+index;
- if (add_shared_memory(config->address,
- vring_size(config->num, PAGE_SIZE))) {
- err = -ENOMEM;
+ err = vmem_add_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
+ if (err)
goto out;
- }
vq = vring_new_virtqueue(config->num, vdev, (void *) config->address,
kvm_notify, callback);
@@ -202,8 +202,8 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
vq->priv = config;
return vq;
unmap:
- remove_shared_memory(config->address, vring_size(config->num,
- PAGE_SIZE));
+ vmem_remove_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
out:
return ERR_PTR(err);
}
@@ -213,8 +213,8 @@ static void kvm_del_vq(struct virtqueue *vq)
struct kvm_vqconfig *config = vq->priv;
vring_del_virtqueue(vq);
- remove_shared_memory(config->address,
- vring_size(config->num, PAGE_SIZE));
+ vmem_remove_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
}
/*
@@ -318,12 +318,13 @@ static int __init kvm_devices_init(void)
return rc;
}
- if (add_shared_memory((max_pfn) << PAGE_SHIFT, PAGE_SIZE)) {
+ rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE);
+ if (rc) {
device_unregister(&kvm_root);
- return -ENOMEM;
+ return rc;
}
- kvm_devices = (void *) (max_pfn << PAGE_SHIFT);
+ kvm_devices = (void *) PFN_PHYS(max_pfn);
ctl_set_bit(0, 9);
register_external_interrupt(0x2603, kvm_extint_handler);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index 76728ae4b84..8e7697305a4 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
{
- const char *start, *end;
- char bus_ids[2][BUS_ID_SIZE], *argv[2];
- int i;
int ret;
struct ccwgroup_driver *cdrv;
cdrv = to_ccwgroupdrv(drv);
if (!cdrv)
return -EINVAL;
- start = buf;
- for (i=0; i<2; i++) {
- static const char delim[] = {',', '\n'};
- int len;
-
- if (!(end = strchr(start, delim[i])))
- return -EINVAL;
- len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
- strlcpy (bus_ids[i], start, len);
- argv[i] = bus_ids[i];
- start = end + 1;
- }
-
- ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
- &cu3088_driver, 2, argv);
+ ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
+ &cu3088_driver, 2, buf);
return (ret == 0) ? count : ret;
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index f51ed997258..dd22f4b3703 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1793,7 +1793,8 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len)
skb->protocol = card->lan_type_trans(skb, card->dev);
card->stats.rx_bytes += skb_len;
card->stats.rx_packets++;
- *((__u32 *)skb->cb) = ++card->pkt_seq;
+ if (skb->protocol == htons(ETH_P_802_2))
+ *((__u32 *)skb->cb) = ++card->pkt_seq;
netif_rx(skb);
}
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 8f876f6ab36..e4ba6a0372a 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1313,8 +1313,6 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
* and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
- if (!in_atomic())
- fsm_event(privptr->fsm, DEV_EVENT_START, dev);
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
@@ -2147,6 +2145,7 @@ static int __init netiucv_init(void)
if (rc)
goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __func__);
+ netiucv_driver.groups = netiucv_drv_attr_groups;
rc = driver_register(&netiucv_driver);
if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 66f4f12503c..699ac11debd 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -72,22 +72,7 @@ struct qeth_dbf_info {
debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text)
#define QETH_DBF_TEXT_(name, level, text...) \
- do { \
- if (qeth_dbf_passes(qeth_dbf[QETH_DBF_##name].id, level)) { \
- char *dbf_txt_buf = \
- get_cpu_var(QETH_DBF_TXT_BUF); \
- sprintf(dbf_txt_buf, text); \
- debug_text_event(qeth_dbf[QETH_DBF_##name].id, \
- level, dbf_txt_buf); \
- put_cpu_var(QETH_DBF_TXT_BUF); \
- } \
- } while (0)
-
-/* Allow to sort out low debug levels early to avoid wasted sprints */
-static inline int qeth_dbf_passes(debug_info_t *dbf_grp, int level)
-{
- return (level <= dbf_grp->level);
-}
+ qeth_dbf_longtext(QETH_DBF_##name, level, text)
/**
* some more debug stuff
@@ -773,27 +758,6 @@ static inline int qeth_get_micros(void)
return (int) (get_clock() >> 12);
}
-static inline void *qeth_push_skb(struct qeth_card *card, struct sk_buff *skb,
- int size)
-{
- void *hdr;
-
- hdr = (void *) skb_push(skb, size);
- /*
- * sanity check, the Linux memory allocation scheme should
- * never present us cases like this one (the qdio header size plus
- * the first 40 bytes of the paket cross a 4k boundary)
- */
- if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
- (((unsigned long) hdr + size +
- QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
- PRINT_ERR("Misaligned packet on interface %s. Discarded.",
- QETH_CARD_IFNAME(card));
- return NULL;
- }
- return hdr;
-}
-
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
switch (skb->protocol) {
@@ -806,6 +770,12 @@ static inline int qeth_get_ip_version(struct sk_buff *skb)
}
}
+static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
+ struct qeth_buffer_pool_entry *entry)
+{
+ list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
+}
+
struct qeth_eddp_context;
extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
@@ -843,8 +813,6 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
int qeth_query_setadapterparms(struct qeth_card *);
int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int,
unsigned int, const char *);
-void qeth_put_buffer_pool_entry(struct qeth_card *,
- struct qeth_buffer_pool_entry *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct qdio_buffer *, struct qdio_buffer_element **, int *,
@@ -880,8 +848,6 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
void *reply_param);
int qeth_get_cast_type(struct qeth_card *, struct sk_buff *);
int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
-struct sk_buff *qeth_prepare_skb(struct qeth_card *, struct sk_buff *,
- struct qeth_hdr **);
int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int);
int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int,
@@ -894,6 +860,8 @@ void qeth_core_get_ethtool_stats(struct net_device *,
struct ethtool_stats *, u64 *);
void qeth_core_get_strings(struct net_device *, u32, u8 *);
void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
+int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 055f5c3e7b5..436bf1f6d4a 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -26,9 +26,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
-static DEFINE_PER_CPU(char[256], qeth_core_dbf_txt_buf);
-#define QETH_DBF_TXT_BUF qeth_core_dbf_txt_buf
-
struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */
/* N P A M L V H */
@@ -2255,14 +2252,6 @@ void qeth_print_status_message(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_print_status_message);
-void qeth_put_buffer_pool_entry(struct qeth_card *card,
- struct qeth_buffer_pool_entry *entry)
-{
- QETH_DBF_TEXT(TRACE, 6, "ptbfplen");
- list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
-}
-EXPORT_SYMBOL_GPL(qeth_put_buffer_pool_entry);
-
static void qeth_initialize_working_pool_list(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@@ -2603,7 +2592,6 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
int rc;
int newcount = 0;
- QETH_DBF_TEXT(TRACE, 6, "queinbuf");
count = (index < queue->next_buf_to_init)?
card->qdio.in_buf_pool.buf_count -
(queue->next_buf_to_init - index) :
@@ -2792,8 +2780,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
int i;
unsigned int qdio_flags;
- QETH_DBF_TEXT(TRACE, 6, "flushbuf");
-
for (i = index; i < index + count; ++i) {
buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
buf->buffer->element[buf->next_element_to_fill - 1].flags |=
@@ -3037,49 +3023,6 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
-static void __qeth_free_new_skb(struct sk_buff *orig_skb,
- struct sk_buff *new_skb)
-{
- if (orig_skb != new_skb)
- dev_kfree_skb_any(new_skb);
-}
-
-static inline struct sk_buff *qeth_realloc_headroom(struct qeth_card *card,
- struct sk_buff *skb, int size)
-{
- struct sk_buff *new_skb = skb;
-
- if (skb_headroom(skb) >= size)
- return skb;
- new_skb = skb_realloc_headroom(skb, size);
- if (!new_skb)
- PRINT_ERR("Could not realloc headroom for qeth_hdr "
- "on interface %s", QETH_CARD_IFNAME(card));
- return new_skb;
-}
-
-struct sk_buff *qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_hdr **hdr)
-{
- struct sk_buff *new_skb;
-
- QETH_DBF_TEXT(TRACE, 6, "prepskb");
-
- new_skb = qeth_realloc_headroom(card, skb,
- sizeof(struct qeth_hdr));
- if (!new_skb)
- return NULL;
-
- *hdr = ((struct qeth_hdr *)qeth_push_skb(card, new_skb,
- sizeof(struct qeth_hdr)));
- if (*hdr == NULL) {
- __qeth_free_new_skb(skb, new_skb);
- return NULL;
- }
- return new_skb;
-}
-EXPORT_SYMBOL_GPL(qeth_prepare_skb);
-
int qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@@ -3100,8 +3043,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
-static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
- int is_tso, int *next_element_to_fill)
+static inline void __qeth_fill_buffer(struct sk_buff *skb,
+ struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill)
{
int length = skb->len;
int length_here;
@@ -3143,15 +3086,13 @@ static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
*next_element_to_fill = element;
}
-static int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
+static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf, struct sk_buff *skb)
{
struct qdio_buffer *buffer;
struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0;
- QETH_DBF_TEXT(TRACE, 6, "qdfillbf");
-
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
@@ -3210,8 +3151,6 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
int flush_cnt = 0;
int index;
- QETH_DBF_TEXT(TRACE, 6, "dosndpfa");
-
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@@ -3263,8 +3202,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
int tmp;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 6, "dosndpkt");
-
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@@ -3827,27 +3764,8 @@ static struct ccw_driver qeth_ccw_driver = {
static int qeth_core_driver_group(const char *buf, struct device *root_dev,
unsigned long driver_id)
{
- const char *start, *end;
- char bus_ids[3][BUS_ID_SIZE], *argv[3];
- int i;
-
- start = buf;
- for (i = 0; i < 3; i++) {
- static const char delim[] = { ',', ',', '\n' };
- int len;
-
- end = strchr(start, delim[i]);
- if (!end)
- return -EINVAL;
- len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
- strncpy(bus_ids[i], start, len);
- bus_ids[i][len] = '\0';
- start = end + 1;
- argv[i] = bus_ids[i];
- }
-
- return (ccwgroup_create(root_dev, driver_id,
- &qeth_ccw_driver, 3, argv));
+ return ccwgroup_create_from_string(root_dev, driver_id,
+ &qeth_ccw_driver, 3, buf);
}
int qeth_core_hardsetup_card(struct qeth_card *card)
@@ -3885,8 +3803,9 @@ retry:
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
return rc;
}
-
- mpno = QETH_MAX_PORTNO;
+ mpno = qdio_get_ssqd_pct(CARD_DDEV(card));
+ if (mpno)
+ mpno = min(mpno - 1, QETH_MAX_PORTNO);
if (card->info.portno > mpno) {
PRINT_ERR("Device %s does not offer port number %d \n.",
CARD_BUS_ID(card), card->info.portno);
@@ -3980,7 +3899,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
int use_rx_sg = 0;
int frag = 0;
- QETH_DBF_TEXT(TRACE, 6, "nextskb");
/* qeth_hdr must not cross element boundaries */
if (element->length < offset + sizeof(struct qeth_hdr)) {
if (qeth_is_last_sbale(element))
@@ -4086,6 +4004,18 @@ static void qeth_unregister_dbf_views(void)
}
}
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...)
+{
+ char dbf_txt_buf[32];
+
+ if (level > (qeth_dbf[dbf_nix].id)->level)
+ return;
+ snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text);
+ debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
+
+}
+EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
+
static int qeth_register_dbf_views(void)
{
int ret;
@@ -4433,6 +4363,96 @@ void qeth_core_get_drvinfo(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo);
+int qeth_core_ethtool_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct qeth_card *card = netdev_priv(netdev);
+ enum qeth_link_types link_type;
+
+ if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan))
+ link_type = QETH_LINK_TYPE_10GBIT_ETH;
+ else
+ link_type = card->info.link_type;
+
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = SUPPORTED_Autoneg;
+ ecmd->advertising = ADVERTISED_Autoneg;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->autoneg = AUTONEG_ENABLE;
+
+ switch (link_type) {
+ case QETH_LINK_TYPE_FAST_ETH:
+ case QETH_LINK_TYPE_LANE_ETH100:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_TP;
+ ecmd->speed = SPEED_100;
+ ecmd->port = PORT_TP;
+ break;
+
+ case QETH_LINK_TYPE_GBIT_ETH:
+ case QETH_LINK_TYPE_LANE_ETH1000:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE;
+ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_FIBRE;
+ break;
+
+ case QETH_LINK_TYPE_10GBIT_ETH:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE;
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ break;
+
+ default:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_TP;
+ ecmd->speed = SPEED_10;
+ ecmd->port = PORT_TP;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);
+
static int __init qeth_core_init(void)
{
int rc;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 3921d1631a7..86ec50ddae1 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -22,9 +22,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
-#define QETH_DBF_TXT_BUF qeth_l2_dbf_txt_buf
-static DEFINE_PER_CPU(char[256], qeth_l2_dbf_txt_buf);
-
static int qeth_l2_set_offline(struct ccwgroup_device *);
static int qeth_l2_stop(struct net_device *);
static int qeth_l2_send_delmac(struct qeth_card *, __u8 *);
@@ -635,8 +632,6 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
- QETH_DBF_TEXT(TRACE, 6, "l2xmit");
-
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_carrier_errors++;
goto tx_drop;
@@ -658,9 +653,12 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data;
else {
- new_skb = qeth_prepare_skb(card, skb, &hdr);
+ /* create a clone with writeable headroom */
+ new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr));
if (!new_skb)
goto tx_drop;
+ hdr = (struct qeth_hdr *)skb_push(new_skb,
+ sizeof(struct qeth_hdr));
qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
}
@@ -747,7 +745,6 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
int index;
int i;
- QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@@ -852,6 +849,22 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
return;
}
+static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+ struct qeth_card *card = netdev_priv(dev);
+
+ if (data) {
+ if (card->options.large_send == QETH_LARGE_SEND_NO) {
+ card->options.large_send = QETH_LARGE_SEND_EDDP;
+ dev->features |= NETIF_F_TSO;
+ }
+ } else {
+ dev->features &= ~NETIF_F_TSO;
+ card->options.large_send = QETH_LARGE_SEND_NO;
+ }
+ return 0;
+}
+
static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_tx_csum = ethtool_op_get_tx_csum,
@@ -859,11 +872,12 @@ static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .set_tso = qeth_l2_ethtool_set_tso,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
+ .get_settings = qeth_core_ethtool_get_settings,
};
static struct ethtool_ops qeth_l2_osn_ops = {
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 1be353593a5..9f143c83bba 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -13,9 +13,6 @@
#include "qeth_core.h"
-#define QETH_DBF_TXT_BUF qeth_l3_dbf_txt_buf
-DECLARE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
-
struct qeth_ipaddr {
struct list_head entry;
enum qeth_ip_types type;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e1bfe56087d..94a8ead64ed 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -28,8 +28,6 @@
#include "qeth_l3.h"
#include "qeth_core_offl.h"
-DEFINE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
-
static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_recover(void *);
static int qeth_l3_stop(struct net_device *);
@@ -2093,6 +2091,11 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
(card->state == CARD_STATE_UP)) {
if (recovery_mode)
qeth_l3_stop(card->dev);
+ else {
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
+ }
if (!card->use_hard_stop) {
rc = qeth_send_stoplan(card);
if (rc)
@@ -2559,8 +2562,6 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
- QETH_DBF_TEXT(TRACE, 6, "fillhdr");
-
memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
hdr->hdr.l3.ext_flags = 0;
@@ -2570,9 +2571,10 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
* v6 uses passthrough, v4 sets the tag in the QDIO header.
*/
if (card->vlangrp && vlan_tx_tag_present(skb)) {
- hdr->hdr.l3.ext_flags = (ipv == 4) ?
- QETH_HDR_EXT_VLAN_FRAME :
- QETH_HDR_EXT_INCLUDE_VLAN_TAG;
+ if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))
+ hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;
+ else
+ hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG;
hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb);
}
@@ -2638,8 +2640,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
- QETH_DBF_TEXT(TRACE, 6, "l3xmit");
-
if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(skb->protocol != htons(ETH_P_IPV6)) &&
(skb->protocol != htons(ETH_P_IP)))
@@ -2890,6 +2890,7 @@ static struct ethtool_ops qeth_l3_ethtool_ops = {
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
+ .get_settings = qeth_core_ethtool_get_settings,
};
/*
@@ -2982,7 +2983,6 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
int index;
int i;
- QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@@ -3140,9 +3140,15 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
netif_carrier_on(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
- if ((recover_flag == CARD_STATE_RECOVER) && recovery_mode) {
+ if (recover_flag == CARD_STATE_RECOVER) {
+ if (recovery_mode)
qeth_l3_open(card->dev);
- qeth_l3_set_multicast_list(card->dev);
+ else {
+ rtnl_lock();
+ dev_open(card->dev);
+ rtnl_unlock();
+ }
+ qeth_l3_set_multicast_list(card->dev);
}
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index a4e75814366..23570341437 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -637,7 +637,7 @@ static int wd_inittimer(int whichdog)
break;
default:
printk("%s: %s: invalid watchdog id: %i\n",
- WD_OBPNAME, __FUNCTION__, whichdog);
+ WD_OBPNAME, __func__, whichdog);
return(1);
}
if(0 != misc_register(whichmisc))
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 44d2ef906ac..383f32c1d34 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -393,13 +393,13 @@ static int __init ts102_uctrl_init(void)
err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
if (err) {
printk("%s: unable to register irq %d\n",
- __FUNCTION__, driver->irq);
+ __func__, driver->irq);
return err;
}
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
- __FUNCTION__, uctrl_dev.minor);
+ __func__, uctrl_dev.minor);
free_irq(driver->irq, driver);
return -ENODEV;
}
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 2b8a410e095..bbf5bc5892c 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -200,7 +200,7 @@ static void rs_stop(struct tty_struct *tty)
local_irq_restore(flags);
}
-static void rs_put_char(char ch)
+static int rs_put_char(char ch)
{
int flags, loops = 0;
@@ -214,6 +214,7 @@ static void rs_put_char(char ch)
UTX_TXDATA = ch;
udelay(5);
local_irq_restore(flags);
+ return 1;
}
static void rs_start(struct tty_struct *tty)
@@ -1017,18 +1018,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(100) : 250);
return 0;
- case TIOCGSOFTCAR:
- error = put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- if (error)
- return error;
- return 0;
- case TIOCSSOFTCAR:
- get_user(arg, (unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
if (access_ok(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_struct)))
@@ -1061,9 +1050,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
-
change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1140,8 +1126,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index f5946360187..d9d4e9552a4 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -995,10 +995,10 @@ static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
volatile QUICC_BD *bdp;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!tty)
- return;
+ return 0;
bdp = info->tx_cur;
while (bdp->status & BD_SC_READY);
@@ -1016,6 +1016,7 @@ static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
bdp++;
info->tx_cur = (QUICC_BD *)bdp;
+ return 1;
}
@@ -1246,7 +1247,7 @@ static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
#ifdef modem_control
unsigned char control, status;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
@@ -1277,12 +1278,12 @@ static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
ser_info_t *info = (ser_info_t *)tty->driver_data;
unsigned int arg;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
-
+ /* FIXME: locking on info->mcr */
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR)
@@ -1436,18 +1437,6 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
return retval;
end_break(info);
return 0;
- case TIOCGSOFTCAR:
- /* return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); */
- put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
- return 0;
- case TIOCSSOFTCAR:
- error = get_user(arg, (unsigned int *) arg);
- if (error)
- return error;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
#ifdef maybe
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
@@ -1665,8 +1654,7 @@ static void rs_360_close(struct tty_struct *tty, struct file * filp)
rs_360_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_360_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
info->event = 0;
@@ -1717,6 +1705,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
printk("jiff=%lu...", jiffies);
#endif
+ lock_kernel();
/* We go through the loop at least once because we can't tell
* exactly when the last character exits the shifter. There can
* be at least two characters waiting to be sent after the buffers
@@ -1745,6 +1734,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
bdp--;
} while (bdp->status & BD_SC_READY);
current->state = TASK_RUNNING;
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 38776e8b064..cd898704ba4 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -156,7 +156,7 @@ static int __init parse_options(struct early_serial8250_device *device,
port->membase = ioremap(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
- __FUNCTION__,
+ __func__,
(unsigned long long)port->mapbase);
return -ENOMEM;
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 34b809e3b59..36acbcca2d4 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1355,4 +1355,47 @@ config SERIAL_SC26XX_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
+config SERIAL_BFIN_SPORT
+ tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
+ depends on BFIN && EXPERIMENTAL
+ select SERIAL_CORE
+ help
+ Enble support SPORT emulate UART on Blackfin series.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_sport_uart.
+
+choice
+ prompt "Baud rate for Blackfin SPORT UART"
+ depends on SERIAL_BFIN_SPORT
+ default SERIAL_SPORT_BAUD_RATE_57600
+ help
+ Choose a baud rate for the SPORT UART, other uart settings are
+ 8 bit, 1 stop bit, no parity, no flow control.
+
+config SERIAL_SPORT_BAUD_RATE_115200
+ bool "115200"
+
+config SERIAL_SPORT_BAUD_RATE_57600
+ bool "57600"
+
+config SERIAL_SPORT_BAUD_RATE_38400
+ bool "38400"
+
+config SERIAL_SPORT_BAUD_RATE_19200
+ bool "19200"
+
+config SERIAL_SPORT_BAUD_RATE_9600
+ bool "9600"
+endchoice
+
+config SPORT_BAUD_RATE
+ int
+ depends on SERIAL_BFIN_SPORT
+ default 115200 if (SERIAL_SPORT_BAUD_RATE_115200)
+ default 57600 if (SERIAL_SPORT_BAUD_RATE_57600)
+ default 38400 if (SERIAL_SPORT_BAUD_RATE_38400)
+ default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
+ default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index f02ff9fad01..0d9c09b1e83 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
+obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 5f55534a290..8a2f6a1baa7 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -762,7 +762,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
break;
default:
printk(KERN_ERR "%s: word lengh not supported\n",
- __FUNCTION__);
+ __func__);
}
if (termios->c_cflag & CSTOPB)
@@ -1029,7 +1029,7 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
*baud = get_sclk() / (16*(dll | dlh << 8));
}
- pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
+ pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
#endif
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
new file mode 100644
index 00000000000..aca1240ad80
--- /dev/null
+++ b/drivers/serial/bfin_sport_uart.c
@@ -0,0 +1,614 @@
+/*
+ * File: linux/drivers/serial/bfin_sport_uart.c
+ *
+ * Based on: drivers/serial/bfin_5xx.c by Aubrey Li.
+ * Author: Roy Huang <roy.huang@analog.com>
+ *
+ * Created: Nov 22, 2006
+ * Copyright: (c) 2006-2007 Analog Devices Inc.
+ * Description: this driver enable SPORTs on Blackfin emulate UART.
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ */
+
+/* After reset, there is a prelude of low level pulse when transmit data first
+ * time. No addtional pulse in following transmit.
+ * According to document:
+ * The SPORTs are ready to start transmitting or receiving data no later than
+ * three serial clock cycles after they are enabled in the SPORTx_TCR1 or
+ * SPORTx_RCR1 register. No serial clock cycles are lost from this point on.
+ * The first internal frame sync will occur one frame sync delay after the
+ * SPORTs are ready. External frame syncs can occur as soon as the SPORT is
+ * ready.
+ */
+
+/* Thanks to Axel Alatalo <axel@rubico.se> for fixing sport rx bug. Sometimes
+ * sport receives data incorrectly. The following is Axel's words.
+ * As EE-191, sport rx samples 3 times of the UART baudrate and takes the
+ * middle smaple of every 3 samples as the data bit. For a 8-N-1 UART setting,
+ * 30 samples will be required for a byte. If transmitter sends a 1/3 bit short
+ * byte due to buadrate drift, then the 30th sample of a byte, this sample is
+ * also the third sample of the stop bit, will happens on the immediately
+ * following start bit which will be thrown away and missed. Thus since parts
+ * of the startbit will be missed and the receiver will begin to drift, the
+ * effect accumulates over time until synchronization is lost.
+ * If only require 2 samples of the stopbit (by sampling in total 29 samples),
+ * then a to short byte as in the case above will be tolerated. Then the 1/3
+ * early startbit will trigger a framesync since the last read is complete
+ * after only 2/3 stopbit and framesync is active during the last 1/3 looking
+ * for a possible early startbit. */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/delay.h>
+#include <asm/portmux.h>
+
+#include "bfin_sport_uart.h"
+
+unsigned short bfin_uart_pin_req_sport0[] =
+ {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+ P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0};
+
+unsigned short bfin_uart_pin_req_sport1[] =
+ {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+ P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0};
+
+#define DRV_NAME "bfin-sport-uart"
+
+struct sport_uart_port {
+ struct uart_port port;
+ char *name;
+
+ int tx_irq;
+ int rx_irq;
+ int err_irq;
+};
+
+static void sport_uart_tx_chars(struct sport_uart_port *up);
+static void sport_stop_tx(struct uart_port *port);
+
+static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
+{
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+ /* Place a Start and Stop bit */
+ __asm__ volatile (
+ "R2 = b#01111111100;\n\t"
+ "R3 = b#10000000001;\n\t"
+ "%0 <<= 2;\n\t"
+ "%0 = %0 & R2;\n\t"
+ "%0 = %0 | R3;\n\t"
+ :"=r"(value)
+ :"0"(value)
+ :"R2", "R3");
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+
+ SPORT_PUT_TX(up, value);
+}
+
+static inline unsigned int rx_one_byte(struct sport_uart_port *up)
+{
+ unsigned int value, extract;
+
+ value = SPORT_GET_RX32(up);
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+
+ /* Extract 8 bits data */
+ __asm__ volatile (
+ "R5 = 0;\n\t"
+ "P0 = 8;\n\t"
+ "R1 = 0x1801(Z);\n\t"
+ "R3 = 0x0300(Z);\n\t"
+ "R4 = 0;\n\t"
+ "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t"
+ "R2 = extract(%1, R1.L)(Z);\n\t"
+ "R2 <<= R4;\n\t"
+ "R5 = R5 | R2;\n\t"
+ "R1 = R1 - R3;\nloop_e:\t"
+ "R4 += 1;\n\t"
+ "%0 = R5;\n\t"
+ :"=r"(extract)
+ :"r"(value)
+ :"P0", "R1", "R2","R3","R4", "R5");
+
+ pr_debug(" extract:%x\n", extract);
+ return extract;
+}
+
+static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
+{
+ int tclkdiv, tfsdiv, rclkdiv;
+
+ /* Set TCR1 and TCR2 */
+ SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
+ SPORT_PUT_TCR2(up, 10);
+ pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+
+ /* Set RCR1 and RCR2 */
+ SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
+ SPORT_PUT_RCR2(up, 28);
+ pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+
+ tclkdiv = sclk/(2 * baud_rate) - 1;
+ tfsdiv = 12;
+ rclkdiv = sclk/(2 * baud_rate * 3) - 1;
+ SPORT_PUT_TCLKDIV(up, tclkdiv);
+ SPORT_PUT_TFSDIV(up, tfsdiv);
+ SPORT_PUT_RCLKDIV(up, rclkdiv);
+ SSYNC();
+ pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
+ __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
+
+ return 0;
+}
+
+static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
+{
+ struct sport_uart_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int ch;
+
+ do {
+ ch = rx_one_byte(up);
+ up->port.icount.rx++;
+
+ if (uart_handle_sysrq_char(&up->port, ch))
+ ;
+ else
+ tty_insert_flip_char(tty, ch, TTY_NORMAL);
+ } while (SPORT_GET_STAT(up) & RXNE);
+ tty_flip_buffer_push(tty);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
+{
+ sport_uart_tx_chars(dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
+{
+ struct sport_uart_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int stat = SPORT_GET_STAT(up);
+
+ /* Overflow in RX FIFO */
+ if (stat & ROVF) {
+ up->port.icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
+ }
+ /* These should not happen */
+ if (stat & (TOVF | TUVF | RUVF)) {
+ printk(KERN_ERR "SPORT Error:%s %s %s\n",
+ (stat & TOVF)?"TX overflow":"",
+ (stat & TUVF)?"TX underflow":"",
+ (stat & RUVF)?"RX underflow":"");
+ SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+ SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+ }
+ SSYNC();
+
+ return IRQ_HANDLED;
+}
+
+/* Reqeust IRQ, Setup clock */
+static int sport_startup(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ char buffer[20];
+ int retval;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ memset(buffer, 20, '\0');
+ snprintf(buffer, 20, "%s rx", up->name);
+ retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ return retval;
+ }
+
+ snprintf(buffer, 20, "%s tx", up->name);
+ retval = request_irq(up->tx_irq, sport_uart_tx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ goto fail1;
+ }
+
+ snprintf(buffer, 20, "%s err", up->name);
+ retval = request_irq(up->err_irq, sport_uart_err_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ goto fail2;
+ }
+
+ if (port->line) {
+ if (peripheral_request_list(bfin_uart_pin_req_sport1, DRV_NAME))
+ goto fail3;
+ } else {
+ if (peripheral_request_list(bfin_uart_pin_req_sport0, DRV_NAME))
+ goto fail3;
+ }
+
+ sport_uart_setup(up, get_sclk(), port->uartclk);
+
+ /* Enable receive interrupt */
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) | RSPEN));
+ SSYNC();
+
+ return 0;
+
+
+fail3:
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+
+ free_irq(up->err_irq, up);
+fail2:
+ free_irq(up->tx_irq, up);
+fail1:
+ free_irq(up->rx_irq, up);
+
+ return retval;
+
+}
+
+static void sport_uart_tx_chars(struct sport_uart_port *up)
+{
+ struct circ_buf *xmit = &up->port.info->xmit;
+
+ if (SPORT_GET_STAT(up) & TXF)
+ return;
+
+ if (up->port.x_char) {
+ tx_one_byte(up, up->port.x_char);
+ up->port.icount.tx++;
+ up->port.x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ sport_stop_tx(&up->port);
+ return;
+ }
+
+ while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
+ tx_one_byte(up, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+ up->port.icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
+}
+
+static unsigned int sport_tx_empty(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned int stat;
+
+ stat = SPORT_GET_STAT(up);
+ pr_debug("%s stat:%04x\n", __FUNCTION__, stat);
+ if (stat & TXHRE) {
+ return TIOCSER_TEMT;
+ } else
+ return 0;
+}
+
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_stop_tx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned int stat;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+
+ stat = SPORT_GET_STAT(up);
+ while(!(stat & TXHRE)) {
+ udelay(1);
+ stat = SPORT_GET_STAT(up);
+ }
+ /* Although the hold register is empty, last byte is still in shift
+ * register and not sent out yet. If baud rate is lower than default,
+ * delay should be longer. For example, if the baud rate is 9600,
+ * the delay must be at least 2ms by experience */
+ udelay(500);
+
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SSYNC();
+
+ return;
+}
+
+static void sport_start_tx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ /* Write data into SPORT FIFO before enable SPROT to transmit */
+ sport_uart_tx_chars(up);
+
+ /* Enable transmit, then an interrupt will generated */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+ SSYNC();
+ pr_debug("%s exit\n", __FUNCTION__);
+}
+
+static void sport_stop_rx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ /* Disable sport to stop rx */
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+ SSYNC();
+}
+
+static void sport_enable_ms(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_break_ctl(struct uart_port *port, int break_state)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_shutdown(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+
+ /* Disable sport */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+ SSYNC();
+
+ if (port->line) {
+ peripheral_free_list(bfin_uart_pin_req_sport1);
+ } else {
+ peripheral_free_list(bfin_uart_pin_req_sport0);
+ }
+
+ free_irq(up->rx_irq, up);
+ free_irq(up->tx_irq, up);
+ free_irq(up->err_irq, up);
+}
+
+static void sport_set_termios(struct uart_port *port,
+ struct termios *termios, struct termios *old)
+{
+ pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag);
+ uart_update_timeout(port, CS8 ,port->uartclk);
+}
+
+static const char *sport_type(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ return up->name;
+}
+
+static void sport_release_port(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static int sport_request_port(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return 0;
+}
+
+static void sport_config_port(struct uart_port *port, int flags)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ up->port.type = PORT_BFIN_SPORT;
+}
+
+static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return 0;
+}
+
+struct uart_ops sport_uart_ops = {
+ .tx_empty = sport_tx_empty,
+ .set_mctrl = sport_set_mctrl,
+ .get_mctrl = sport_get_mctrl,
+ .stop_tx = sport_stop_tx,
+ .start_tx = sport_start_tx,
+ .stop_rx = sport_stop_rx,
+ .enable_ms = sport_enable_ms,
+ .break_ctl = sport_break_ctl,
+ .startup = sport_startup,
+ .shutdown = sport_shutdown,
+ .set_termios = sport_set_termios,
+ .type = sport_type,
+ .release_port = sport_release_port,
+ .request_port = sport_request_port,
+ .config_port = sport_config_port,
+ .verify_port = sport_verify_port,
+};
+
+static struct sport_uart_port sport_uart_ports[] = {
+ { /* SPORT 0 */
+ .name = "SPORT0",
+ .tx_irq = IRQ_SPORT0_TX,
+ .rx_irq = IRQ_SPORT0_RX,
+ .err_irq= IRQ_SPORT0_ERROR,
+ .port = {
+ .type = PORT_BFIN_SPORT,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)SPORT0_TCR1,
+ .mapbase = SPORT0_TCR1,
+ .irq = IRQ_SPORT0_RX,
+ .uartclk = CONFIG_SPORT_BAUD_RATE,
+ .fifosize = 8,
+ .ops = &sport_uart_ops,
+ .line = 0,
+ },
+ }, { /* SPORT 1 */
+ .name = "SPORT1",
+ .tx_irq = IRQ_SPORT1_TX,
+ .rx_irq = IRQ_SPORT1_RX,
+ .err_irq= IRQ_SPORT1_ERROR,
+ .port = {
+ .type = PORT_BFIN_SPORT,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)SPORT1_TCR1,
+ .mapbase = SPORT1_TCR1,
+ .irq = IRQ_SPORT1_RX,
+ .uartclk = CONFIG_SPORT_BAUD_RATE,
+ .fifosize = 8,
+ .ops = &sport_uart_ops,
+ .line = 1,
+ },
+ }
+};
+
+static struct uart_driver sport_uart_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "SPORT-UART",
+ .dev_name = "ttySS",
+ .major = 204,
+ .minor = 84,
+ .nr = ARRAY_SIZE(sport_uart_ports),
+ .cons = NULL,
+};
+
+static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ if (sport)
+ uart_suspend_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static int sport_uart_resume(struct platform_device *dev)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ if (sport)
+ uart_resume_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static int sport_uart_probe(struct platform_device *dev)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ sport_uart_ports[dev->id].port.dev = &dev->dev;
+ uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
+ platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
+
+ return 0;
+}
+
+static int sport_uart_remove(struct platform_device *dev)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ platform_set_drvdata(dev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static struct platform_driver sport_uart_driver = {
+ .probe = sport_uart_probe,
+ .remove = sport_uart_remove,
+ .suspend = sport_uart_suspend,
+ .resume = sport_uart_resume,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init sport_uart_init(void)
+{
+ int ret;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ ret = uart_register_driver(&sport_uart_reg);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register %s:%d\n",
+ sport_uart_reg.driver_name, ret);
+ return ret;
+ }
+
+ ret = platform_driver_register(&sport_uart_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register sport uart driver:%d\n", ret);
+ uart_unregister_driver(&sport_uart_reg);
+ }
+
+
+ pr_debug("%s exit\n", __FUNCTION__);
+ return ret;
+}
+
+static void __exit sport_uart_exit(void)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ platform_driver_unregister(&sport_uart_driver);
+ uart_unregister_driver(&sport_uart_reg);
+}
+
+module_init(sport_uart_init);
+module_exit(sport_uart_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
new file mode 100644
index 00000000000..671d41cc1a3
--- /dev/null
+++ b/drivers/serial/bfin_sport_uart.h
@@ -0,0 +1,63 @@
+/*
+ * File: linux/drivers/serial/bfin_sport_uart.h
+ *
+ * Based on: include/asm-blackfin/mach-533/bfin_serial_5xx.h
+ * Author: Roy Huang <roy.huang>analog.com>
+ *
+ * Created: Nov 22, 2006
+ * Copyright: (C) Analog Device Inc.
+ * Description: this driver enable SPORTs on Blackfin emulate UART.
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */
+#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */
+#define OFFSET_TCLKDIV 0x08 /* Transmit Serial Clock Divider Register */
+#define OFFSET_TFSDIV 0x0C /* Transmit Frame Sync Divider Register */
+#define OFFSET_TX 0x10 /* Transmit Data Register */
+#define OFFSET_RX 0x18 /* Receive Data Register */
+#define OFFSET_RCR1 0x20 /* Receive Configuration 1 Register */
+#define OFFSET_RCR2 0x24 /* Receive Configuration 2 Register */
+#define OFFSET_RCLKDIV 0x28 /* Receive Serial Clock Divider Register */
+#define OFFSET_RFSDIV 0x2c /* Receive Frame Sync Divider Register */
+#define OFFSET_STAT 0x30 /* Status Register */
+
+#define SPORT_GET_TCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR1))
+#define SPORT_GET_TCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR2))
+#define SPORT_GET_TCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
+#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
+#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX))
+#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX))
+#define SPORT_GET_RX32(sport) bfin_read32(((sport)->port.membase + OFFSET_RX))
+#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))
+#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2))
+#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
+#define SPORT_GET_RFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
+#define SPORT_GET_STAT(sport) bfin_read16(((sport)->port.membase + OFFSET_STAT))
+
+#define SPORT_PUT_TCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
+#define SPORT_PUT_TCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
+#define SPORT_PUT_TCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
+#define SPORT_PUT_TFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
+#define SPORT_PUT_TX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TX), v)
+#define SPORT_PUT_RX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RX), v)
+#define SPORT_PUT_RCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
+#define SPORT_PUT_RCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
+#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
+#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
+#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index a638ba0679a..a19dc7ef886 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -1117,7 +1117,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
line = cpm_uart_id2nr(idx);
if(line < 0) {
- printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
+ printk(KERN_ERR"%s(): port %d is not registered", __func__, idx);
return -EINVAL;
}
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 88e7c1d5b91..f9fa237aa94 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -1788,7 +1788,7 @@ static unsigned int handle_descr_data(struct e100_serial *info,
if (info->recv_cnt + recvl > 65536) {
printk(KERN_CRIT
- "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl);
+ "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
return 0;
}
@@ -1801,7 +1801,7 @@ static unsigned int handle_descr_data(struct e100_serial *info,
append_recv_buffer(info, buffer);
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
- panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr->buf = virt_to_phys(buffer->buffer);
@@ -1925,7 +1925,7 @@ static int start_recv_dma(struct e100_serial *info)
/* Set up the receiving descriptors */
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
- panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr[i].ctrl = d_int;
descr[i].buf = virt_to_phys(buffer->buffer);
@@ -3581,8 +3581,9 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
- lock_kernel();
+ local_irq_save(flags);
if (clear & TIOCM_RTS)
e100_rts(info, 0);
@@ -3604,7 +3605,7 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
if (set & TIOCM_CD)
e100_cd_out(info, 1);
- unlock_kernel();
+ local_irq_restore(flags);
return 0;
}
@@ -3613,8 +3614,10 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned int result;
+ unsigned long flags;
+
+ local_irq_save(flags);
- lock_kernel();
result =
(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
@@ -3623,7 +3626,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
- unlock_kernel();
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_IO
printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
@@ -3702,10 +3705,6 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
-
change_speed(info);
/* Handle turning off CRTSCTS */
@@ -3808,10 +3807,8 @@ rs_close(struct tty_struct *tty, struct file * filp)
#endif
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
+ rs_flush_buffer(tty);
+ tty_ldisc_flush_buffer(tty);
tty->closing = 0;
info->event = 0;
info->tty = 0;
@@ -3885,6 +3882,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
* Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
* R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
*/
+ lock_kernel();
orig_jiffies = jiffies;
while (info->xmit.head != info->xmit.tail || /* More in send queue */
(*info->ostatusadr & 0x007f) || /* more in FIFO */
@@ -3901,6 +3899,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
curr_time_usec - info->last_tx_active_usec;
}
set_current_state(TASK_RUNNING);
+ unlock_kernel();
}
/*
@@ -4520,7 +4519,7 @@ rs_init(void)
if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
- panic("%s: Failed to request irq8", __FUNCTION__);
+ panic("%s: Failed to request irq8", __func__);
#endif
#endif /* CONFIG_SVINTO_SIM */
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 168073f12ce..4f1af71e9a1 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -52,7 +52,7 @@ static unsigned int Submodule_slot;
#define DPRINT_CONFIG(_x...) ;
//#define DPRINT_CONFIG(_x...) printk _x
#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS() printk("%s : fails %d\n", __FUNCTION__, __LINE__)
+//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__)
/* number of characters we want to transmit to the lower level at a time */
#define MAX_CHARS 256
@@ -445,7 +445,7 @@ static int inline port_init(struct ioc3_port *port)
sbbr_h = &idd->vma->sbbr_h;
ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
- __FUNCTION__, (void *)ring_pci_addr));
+ __func__, (void *)ring_pci_addr));
writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
@@ -593,7 +593,7 @@ config_port(struct ioc3_port *port,
DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
"parodd %d\n",
- __FUNCTION__, ((struct uart_port *)port->ip_port)->line,
+ __func__, ((struct uart_port *)port->ip_port)->line,
baud, byte_size, stop_bits, parenb, parodd));
if (set_baud(port, baud))
@@ -871,14 +871,14 @@ static int ioc3_set_proto(struct ioc3_port *port, int proto)
default:
case PROTO_RS232:
/* Clear the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs232\n", __FUNCTION__));
+ DPRINT_CONFIG(("%s: rs232\n", __func__));
writel(0, (&port->ip_idd->vma->gppr[0]
+ hooks->rs422_select_pin));
break;
case PROTO_RS422:
/* Set the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs422\n", __FUNCTION__));
+ DPRINT_CONFIG(("%s: rs422\n", __func__));
writel(1, (&port->ip_idd->vma->gppr[0]
+ hooks->rs422_select_pin));
break;
@@ -988,7 +988,7 @@ ioc3_change_speed(struct uart_port *the_port,
}
baud = uart_get_baud_rate(the_port, new_termios, old_termios,
MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __FUNCTION__, baud,
+ DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
the_port->line));
if (!the_port->fifosize)
@@ -1026,7 +1026,7 @@ ioc3_change_speed(struct uart_port *the_port,
DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
"config_port(baud %d data %d stop %d penable %d "
" parity %d), notification 0x%x\n",
- __FUNCTION__, (void *)port, the_port->line, cflag, baud,
+ __func__, (void *)port, the_port->line, cflag, baud,
new_data, new_stop, new_parity_enable, new_parity,
the_port->ignore_status_mask));
@@ -1919,7 +1919,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
struct pci_dev *pdev = idd->pdev;
DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
- __FUNCTION__, pdev, (void *)card_ptr));
+ __func__, pdev, (void *)card_ptr));
if (!card_ptr)
return -ENODEV;
@@ -1933,7 +1933,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
port->ip_port = the_port;
DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
- __FUNCTION__, (void *)the_port, (void *)port,
+ __func__, (void *)the_port, (void *)port,
phys_port, ii));
/* membase, iobase and mapbase just need to be non-0 */
@@ -1950,7 +1950,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
printk(KERN_WARNING
"%s: unable to add port %d bus %d\n",
- __FUNCTION__, the_port->line, pdev->bus->number);
+ __func__, the_port->line, pdev->bus->number);
} else {
DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
the_port->line, the_port->irq, pdev->bus->number));
@@ -2017,7 +2017,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
struct ioc3_port *ports[PORTS_PER_CARD];
int phys_port;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd));
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
if (!card_ptr) {
@@ -2067,7 +2067,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
"ip_uart_regs 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_serial_regs,
(void *)port->ip_uart_regs));
@@ -2082,7 +2082,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p, ip_inring 0x%p "
"ip_outring 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf,
(void *)port->ip_inring,
@@ -2094,7 +2094,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
"ip_uart_regs 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_serial_regs,
(void *)port->ip_uart_regs));
@@ -2108,7 +2108,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p, ip_inring 0x%p "
"ip_outring 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf,
(void *)port->ip_inring,
@@ -2116,7 +2116,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
}
DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
- __FUNCTION__,
+ __func__,
phys_port, (void *)port, (void *)card_ptr));
DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
(void *)port->ip_serial_regs,
@@ -2127,7 +2127,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
"outring 0x%p\n",
- __FUNCTION__,
+ __func__,
phys_port, (void *)port,
(void *)port->ip_inring,
(void *)port->ip_outring));
@@ -2170,7 +2170,7 @@ static int __devinit ioc3uart_init(void)
if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register IOC3 uart serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
ret = ioc3_register_submodule(&ioc3uart_submodule);
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 0c179384fb0..49b8a82b7b9 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -889,7 +889,7 @@ static int inline port_init(struct ioc4_port *port)
ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
- __FUNCTION__, ring_pci_addr));
+ __func__, ring_pci_addr));
writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
@@ -1028,7 +1028,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg)
spin_lock_irqsave(&soft->is_ir_lock, flag);
printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
"other_ir 0x%x other_ies 0x%x mask 0x%x\n",
- __FUNCTION__, __LINE__,
+ __func__, __LINE__,
(void *)mem, readl(&mem->sio_ir.raw),
readl(&mem->sio_ies.raw),
readl(&mem->other_ir.raw),
@@ -1155,14 +1155,14 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
(TOTAL_RING_BUF_SIZE - 1)) == 0));
DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf));
port->ip_inring = RING(port, RX_0_OR_2);
port->ip_outring = RING(port, TX_0_OR_2);
}
DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
- __FUNCTION__,
+ __func__,
port_number, (void *)port, (void *)control));
DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
(void *)port->ip_serial_regs,
@@ -1173,7 +1173,7 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
"outring 0x%p\n",
- __FUNCTION__,
+ __func__,
port_number, (void *)port,
(void *)port->ip_inring,
(void *)port->ip_outring));
@@ -1317,7 +1317,7 @@ config_port(struct ioc4_port *port,
int spiniter = 0;
DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
- __FUNCTION__, baud, byte_size, stop_bits, parenb, parodd));
+ __func__, baud, byte_size, stop_bits, parenb, parodd));
if (set_baud(port, baud))
return 1;
@@ -1725,7 +1725,7 @@ ioc4_change_speed(struct uart_port *the_port,
}
baud = uart_get_baud_rate(the_port, new_termios, old_termios,
MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d\n", __FUNCTION__, baud));
+ DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
/* default is 9600 */
if (!baud)
@@ -1765,7 +1765,7 @@ ioc4_change_speed(struct uart_port *the_port,
DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
"config_port(baud %d data %d stop %d p enable %d parity %d),"
" notification 0x%x\n",
- __FUNCTION__, (void *)port, cflag, baud, new_data, new_stop,
+ __func__, (void *)port, cflag, baud, new_data, new_stop,
new_parity_enable, new_parity, the_port->ignore_status_mask));
if ((config_port(port, baud, /* baud */
@@ -2715,7 +2715,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
- __FUNCTION__, pdev, (void *)control));
+ __func__, pdev, (void *)control));
if (!control)
return -ENODEV;
@@ -2734,7 +2734,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
port->ip_all_ports[port_type_idx] = the_port;
DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
- __FUNCTION__, (void *)the_port,
+ __func__, (void *)the_port,
(void *)port,
port_type == PROTO_RS232 ? "rs232" : "rs422"));
@@ -2752,7 +2752,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
if (uart_add_one_port(u_driver, the_port) < 0) {
printk(KERN_WARNING
"%s: unable to add port %d bus %d\n",
- __FUNCTION__, the_port->line, pdev->bus->number);
+ __func__, the_port->line, pdev->bus->number);
} else {
DPRINT_CONFIG(
("IOC4 serial port %d irq = %d, bus %d\n",
@@ -2777,7 +2777,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
int ret = 0;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev,
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
idd->idd_pci_id));
/* PCI-RT does not bring out serial connections.
@@ -2806,7 +2806,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
goto out2;
}
DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
- __FUNCTION__, (void *)idd->idd_misc_regs,
+ __func__, (void *)idd->idd_misc_regs,
(void *)serial));
/* Get memory for the new card */
@@ -2858,7 +2858,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
} else {
printk(KERN_WARNING
"%s : request_irq fails for IRQ 0x%x\n ",
- __FUNCTION__, idd->idd_pdev->irq);
+ __func__, idd->idd_pdev->irq);
}
ret = ioc4_attach_local(idd);
if (ret)
@@ -2911,13 +2911,13 @@ int ioc4_serial_init(void)
if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register rs232 IOC4 serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register rs422 IOC4 serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index 9cf03327386..eadc1ab6bbc 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -96,12 +96,14 @@ static void cleanup_kgdboc(void)
static int kgdboc_get_char(void)
{
- return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line);
+ return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
+ kgdb_tty_line);
}
static void kgdboc_put_char(u8 chr)
{
- kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr);
+ kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
+ kgdb_tty_line, chr);
}
static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index ddd3aa50d4a..43af40d59b8 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -1072,18 +1072,6 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0;
- case TIOCGSOFTCAR:
- error = put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- if (error)
- return error;
- return 0;
- case TIOCSSOFTCAR:
- get_user(arg, (unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
if (access_ok(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_struct)))
@@ -1222,8 +1210,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp)
} else
#endif
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mcfrs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1276,6 +1263,8 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
+ lock_kernel();
+
fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
char_time = fifo_time / 5;
if (char_time == 0)
@@ -1312,6 +1301,7 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
+ unlock_kernel();
#else
/*
* For the other coldfire models, assume all data has been sent
@@ -1907,7 +1897,7 @@ static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
* This is used for console output.
*/
-void mcfrs_put_char(char ch)
+int mcfrs_put_char(char ch)
{
volatile unsigned char *uartp;
unsigned long flags;
@@ -1931,7 +1921,7 @@ void mcfrs_put_char(char ch)
mcfrs_init_console(); /* try and get it back */
local_irq_restore(flags);
- return;
+ return 1;
}
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index d93b3578c5e..7a3625f52a0 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -1221,8 +1221,8 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
#endif
#ifdef CONFIG_PPC_MPC512x
{ .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
- {},
#endif
+ {},
};
static int __devinit
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index 3123ffeac8a..81ac9bb4f39 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -287,6 +287,7 @@ static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned int val;
+ /* FIXME: Locking needed ? */
if (mctrl & TIOCM_RTS) {
val = readl(port->membase + UART_RTS_CR);
writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index da5a02cb4f6..2b6a013639e 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1096,13 +1096,13 @@ static int s3c24xx_serial_probe(struct platform_device *dev,
ourport = &s3c24xx_serial_ports[probe_index];
probe_index++;
- dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);
+ dbg("%s: initialising port %p...\n", __func__, ourport);
ret = s3c24xx_serial_init_port(ourport, info, dev);
if (ret < 0)
goto probe_err;
- dbg("%s: adding port\n", __FUNCTION__);
+ dbg("%s: adding port\n", __func__);
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
platform_set_drvdata(dev, &ourport->port);
@@ -1587,7 +1587,7 @@ static int s3c2412_serial_resetport(struct uart_port *port,
unsigned long ucon = rd_regl(port, S3C2410_UCON);
dbg("%s: port=%p (%08lx), cfg=%p\n",
- __FUNCTION__, port, port->mapbase, cfg);
+ __func__, port, port->mapbase, cfg);
/* ensure we don't change the clock settings... */
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index 67b2338913c..62b38582f5e 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -655,7 +655,7 @@ void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns)
void __init sa1100_register_uart(int idx, int port)
{
if (idx >= NR_PORTS) {
- printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx);
+ printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
return;
}
@@ -682,7 +682,7 @@ void __init sa1100_register_uart(int idx, int port)
break;
default:
- printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port);
+ printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
}
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 977ce820ce3..1e2b9d826f6 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -422,6 +422,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
EXPORT_SYMBOL(uart_get_divisor);
+/* FIXME: Consistent locking policy */
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
@@ -454,27 +455,30 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
port->ops->set_termios(port, termios, old_termios);
}
-static inline void
+static inline int
__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
{
unsigned long flags;
+ int ret = 0;
if (!circ->buf)
- return;
+ return 0;
spin_lock_irqsave(&port->lock, flags);
if (uart_circ_chars_free(circ) != 0) {
circ->buf[circ->head] = c;
circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+ ret = 1;
}
spin_unlock_irqrestore(&port->lock, flags);
+ return ret;
}
-static void uart_put_char(struct tty_struct *tty, unsigned char ch)
+static int uart_put_char(struct tty_struct *tty, unsigned char ch)
{
struct uart_state *state = tty->driver_data;
- __uart_put_char(state->port, &state->info->xmit, ch);
+ return __uart_put_char(state->port, &state->info->xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
@@ -528,15 +532,25 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
static int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_free(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_free(&state->info->xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_pending(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_pending(&state->info->xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static void uart_flush_buffer(struct tty_struct *tty)
@@ -618,6 +632,11 @@ static int uart_get_info(struct uart_state *state,
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
+
+ /* Ensure the state we copy is consistent and no hardware changes
+ occur as we go */
+ mutex_lock(&state->mutex);
+
tmp.type = port->type;
tmp.line = port->line;
tmp.port = port->iobase;
@@ -637,6 +656,8 @@ static int uart_get_info(struct uart_state *state,
tmp.iomem_reg_shift = port->regshift;
tmp.iomem_base = (void *)(unsigned long)port->mapbase;
+ mutex_unlock(&state->mutex);
+
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -914,8 +935,6 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
- BUG_ON(!kernel_locked());
-
mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN)
@@ -1059,7 +1078,7 @@ static int uart_get_count(struct uart_state *state,
}
/*
- * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
+ * Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
@@ -1069,7 +1088,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
- BUG_ON(!kernel_locked());
/*
* These ioctls don't rely on the hardware to be present.
@@ -1140,9 +1158,9 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
break;
}
}
- out_up:
+out_up:
mutex_unlock(&state->mutex);
- out:
+out:
return ret;
}
@@ -1153,7 +1171,6 @@ static void uart_set_termios(struct tty_struct *tty,
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
- BUG_ON(!kernel_locked());
/*
* These are the bits that are used to setup various
@@ -1165,8 +1182,9 @@ static void uart_set_termios(struct tty_struct *tty,
if ((cflag ^ old_termios->c_cflag) == 0 &&
tty->termios->c_ospeed == old_termios->c_ospeed &&
tty->termios->c_ispeed == old_termios->c_ispeed &&
- RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
return;
+ }
uart_change_speed(state, old_termios);
@@ -1200,7 +1218,6 @@ static void uart_set_termios(struct tty_struct *tty,
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
-
#if 0
/*
* No need to wake up processes in open wait, since they
@@ -1316,11 +1333,11 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
struct uart_port *port = state->port;
unsigned long char_time, expire;
- BUG_ON(!kernel_locked());
-
if (port->type == PORT_UNKNOWN || port->fifosize == 0)
return;
+ lock_kernel();
+
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -1366,6 +1383,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
set_current_state(TASK_RUNNING); /* might not be needed */
+ unlock_kernel();
}
/*
@@ -2079,7 +2097,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
int ret;
uart_change_pm(state, 0);
+ spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
+ spin_unlock_irq(&port->lock);
ret = ops->startup(port);
if (ret == 0) {
uart_change_speed(state, NULL);
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index c2ea5d4df44..96910618771 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -855,7 +855,7 @@ static int sci_notifier(struct notifier_block *self,
printk(KERN_INFO "%s: got a postchange notification "
"for cpu %d (old %d, new %d)\n",
- __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+ __func__, freqs->cpu, freqs->old, freqs->new);
}
return NOTIFY_OK;
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 41fc6126444..019da2e05f0 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -839,7 +839,7 @@ static int __init sn_sal_module_init(void)
if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
/* error - not sure what I'd do - so I'll do nothing */
- printk(KERN_ERR "%s: unable to add port\n", __FUNCTION__);
+ printk(KERN_ERR "%s: unable to add port\n", __func__);
}
/* when this driver is compiled in, the console initialization
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index b565d5a3749..b51c24245be 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -584,7 +584,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match)
const unsigned int *id;
int irq, rc;
- dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match);
+ dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
rc = of_address_to_resource(op->node, 0, &res);
if (rc) {
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 5e4310ccd59..01917c433f1 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -215,7 +215,7 @@ static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%p\n", __FUNCTION__, addr);
+ printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
BUG();
return 0;
}
@@ -234,7 +234,7 @@ static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%x\n", __FUNCTION__, addr);
+ printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
BUG();
return NULL;
}
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 02c8e305b14..e81d59d7891 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -497,7 +497,7 @@ static int atmel_spi_setup(struct spi_device *spi)
struct atmel_spi *as;
u32 scbr, csr;
unsigned int bits = spi->bits_per_word;
- unsigned long bus_hz, sck_hz;
+ unsigned long bus_hz;
unsigned int npcs_pin;
int ret;
@@ -536,14 +536,25 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
- /* speed zero convention is used by some upper layers */
+ /*
+ * Pre-new_1 chips start out at half the peripheral
+ * bus speed.
+ */
bus_hz = clk_get_rate(as->clk);
+ if (!as->new_1)
+ bus_hz /= 2;
+
if (spi->max_speed_hz) {
- /* assume div32/fdiv/mbz == 0 */
- if (!as->new_1)
- bus_hz /= 2;
- scbr = ((bus_hz + spi->max_speed_hz - 1)
- / spi->max_speed_hz);
+ /*
+ * Calculate the lowest divider that satisfies the
+ * constraint, assuming div32/fdiv/mbz == 0.
+ */
+ scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz);
+
+ /*
+ * If the resulting divider doesn't fit into the
+ * register bitfield, we can't satisfy the constraint.
+ */
if (scbr >= (1 << SPI_SCBR_SIZE)) {
dev_dbg(&spi->dev,
"setup: %d Hz too slow, scbr %u; min %ld Hz\n",
@@ -551,8 +562,8 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
} else
+ /* speed zero means "as slow as possible" */
scbr = 0xff;
- sck_hz = bus_hz / scbr;
csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
if (spi->mode & SPI_CPOL)
@@ -589,7 +600,7 @@ static int atmel_spi_setup(struct spi_device *spi)
dev_dbg(&spi->dev,
"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
- sck_hz, bits, spi->mode, spi->chip_select, csr);
+ bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 433b3f44f42..8d158e5640e 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -170,7 +170,7 @@ static int gs_open(struct tty_struct *tty, struct file *file);
static void gs_close(struct tty_struct *tty, struct file *file);
static int gs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
-static void gs_put_char(struct tty_struct *tty, unsigned char ch);
+static int gs_put_char(struct tty_struct *tty, unsigned char ch);
static void gs_flush_chars(struct tty_struct *tty);
static int gs_write_room(struct tty_struct *tty);
static int gs_chars_in_buffer(struct tty_struct *tty);
@@ -883,14 +883,15 @@ exit:
/*
* gs_put_char
*/
-static void gs_put_char(struct tty_struct *tty, unsigned char ch)
+static int gs_put_char(struct tty_struct *tty, unsigned char ch)
{
unsigned long flags;
struct gs_port *port = tty->driver_data;
+ int ret = 0;
if (port == NULL) {
pr_err("gs_put_char: NULL port pointer\n");
- return;
+ return 0;
}
gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
@@ -910,10 +911,11 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
goto exit;
}
- gs_buf_put(port->port_write_buf, &ch, 1);
+ ret = gs_buf_put(port->port_write_buf, &ch, 1);
exit:
spin_unlock_irqrestore(&port->port_lock, flags);
+ return ret;
}
/*
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index d17d1645714..04a56f300ea 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1421,8 +1421,7 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
if (port->serial->dev) {
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index a9934a3f984..0cb0d77dc42 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -296,16 +296,14 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
+ if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
- if (!port->open_count) {
- retval = -EINVAL;
- dbg("%s - port not opened", __func__);
- goto exit;
- }
+ /* open_count is managed under the mutex lock for the tty so cannot
+ drop to zero until after the last close completes */
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
retval = port->serial->type->write(port, buf, count);
@@ -317,61 +315,28 @@ exit:
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
dbg("%s - port %d", __func__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- goto exit;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->write_room(port);
-
-exit:
- return retval;
+ return port->serial->type->write_room(port);
}
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
dbg("%s = port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- goto exit;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->chars_in_buffer(port);
-
-exit:
- return retval;
+ return port->serial->type->chars_in_buffer(port);
}
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg ("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(port);
@@ -380,17 +345,9 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(port);
@@ -401,42 +358,27 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- lock_kernel();
- if (!port)
- goto exit;
-
dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
- /* Caution - port->open_count is BKL protected */
- if (!port->open_count) {
- dbg ("%s - port not open", __func__);
- goto exit;
- }
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->ioctl)
+ if (port->serial->type->ioctl) {
+ lock_kernel();
retval = port->serial->type->ioctl(port, file, cmd, arg);
+ unlock_kernel();
+ }
else
retval = -ENOIOCTLCMD;
-exit:
- unlock_kernel();
return retval;
}
static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(port, old);
@@ -448,24 +390,15 @@ static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- lock_kernel();
- if (!port) {
- unlock_kernel();
- return;
- }
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- unlock_kernel();
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->break_ctl)
+ if (port->serial->type->break_ctl) {
+ lock_kernel();
port->serial->type->break_ctl(port, break_state);
- unlock_kernel();
+ unlock_kernel();
+ }
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
@@ -519,19 +452,11 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return -ENODEV;
- }
-
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(port, file);
-
return -EINVAL;
}
@@ -540,19 +465,11 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return -ENODEV;
- }
-
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(port, file, set, clear);
-
return -EINVAL;
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index e96bf8663ff..f07e8a4c1f3 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -673,15 +673,13 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
}
*/
- if (port->tty->driver->flush_buffer)
- port->tty->driver->flush_buffer(port->tty);
+ tty_driver_flush_buffer(port->tty);
tty_ldisc_flush(port->tty);
firm_report_tx_done(port);
firm_close(port);
-printk(KERN_ERR"Before processing rx_urbs_submitted.\n");
/* shutdown our bulk reads and writes */
mutex_lock(&info->deathwarrant);
spin_lock_irq(&info->lock);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a576dc26173..bb1dadaa4a2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1774,6 +1774,11 @@ config FB_PXA
If unsure, say N.
+config FB_PXA_SMARTPANEL
+ bool "PXA Smartpanel LCD support"
+ default n
+ depends on FB_PXA
+
config FB_PXA_PARAMETERS
bool "PXA LCD command line parameters"
default n
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 757651954e6..3ab6e3d973a 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -39,6 +39,9 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -57,19 +60,31 @@
#include "pxafb.h"
/* Bits which should not be set in machine configuration structures */
-#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
-#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
+#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM | LCCR0_BM | LCCR0_QDM |\
+ LCCR0_DIS | LCCR0_EFM | LCCR0_IUM |\
+ LCCR0_SFM | LCCR0_LDM | LCCR0_ENB)
+
+#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP | LCCR3_VSP |\
+ LCCR3_PCD | LCCR3_BPP)
static void (*pxafb_backlight_power)(int);
static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
-static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+static int pxafb_activate_var(struct fb_var_screeninfo *var,
+ struct pxafb_info *);
static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
-#ifdef CONFIG_FB_PXA_PARAMETERS
-#define PXAFB_OPTIONS_SIZE 256
-static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
-#endif
+static inline unsigned long
+lcd_readl(struct pxafb_info *fbi, unsigned int off)
+{
+ return __raw_readl(fbi->mmio_base + off);
+}
+
+static inline void
+lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
+{
+ __raw_writel(val, fbi->mmio_base + off);
+}
static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
{
@@ -79,10 +94,12 @@ static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
/*
* We need to handle two requests being made at the same time.
* There are two important cases:
- * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
- * We must perform the unblanking, which will do our REENABLE for us.
- * 2. When we are blanking, but immediately unblank before we have
- * blanked. We do the "REENABLE" thing here as well, just to be sure.
+ * 1. When we are changing VT (C_REENABLE) while unblanking
+ * (C_ENABLE) We must perform the unblanking, which will
+ * do our REENABLE for us.
+ * 2. When we are blanking, but immediately unblank before
+ * we have blanked. We do the "REENABLE" thing here as
+ * well, just to be sure.
*/
if (fbi->task_state == C_ENABLE && state == C_REENABLE)
state = (u_int) -1;
@@ -129,13 +146,13 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
val = ((red << 8) & 0x00f80000);
val |= ((green >> 0) & 0x0000fc00);
val |= ((blue >> 8) & 0x000000f8);
- ((u32*)(fbi->palette_cpu))[regno] = val;
+ ((u32 *)(fbi->palette_cpu))[regno] = val;
break;
case LCCR4_PAL_FOR_2:
val = ((red << 8) & 0x00fc0000);
val |= ((green >> 0) & 0x0000fc00);
val |= ((blue >> 8) & 0x000000fc);
- ((u32*)(fbi->palette_cpu))[regno] = val;
+ ((u32 *)(fbi->palette_cpu))[regno] = val;
break;
}
@@ -203,15 +220,15 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
*/
static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
{
- int ret = 0;
- switch (var->bits_per_pixel) {
- case 1: ret = LCCR3_1BPP; break;
- case 2: ret = LCCR3_2BPP; break;
- case 4: ret = LCCR3_4BPP; break;
- case 8: ret = LCCR3_8BPP; break;
- case 16: ret = LCCR3_16BPP; break;
- }
- return ret;
+ int ret = 0;
+ switch (var->bits_per_pixel) {
+ case 1: ret = LCCR3_1BPP; break;
+ case 2: ret = LCCR3_2BPP; break;
+ case 4: ret = LCCR3_4BPP; break;
+ case 8: ret = LCCR3_8BPP; break;
+ case 16: ret = LCCR3_16BPP; break;
+ }
+ return ret;
}
#ifdef CONFIG_CPU_FREQ
@@ -223,31 +240,32 @@ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
*/
static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
{
- /*
- * Period = pixclock * bits_per_byte * bytes_per_transfer
- * / memory_bits_per_pixel;
- */
- return var->pixclock * 8 * 16 / var->bits_per_pixel;
+ /*
+ * Period = pixclock * bits_per_byte * bytes_per_transfer
+ * / memory_bits_per_pixel;
+ */
+ return var->pixclock * 8 * 16 / var->bits_per_pixel;
}
-
-extern unsigned int get_clk_frequency_khz(int info);
#endif
/*
* Select the smallest mode that allows the desired resolution to be
* displayed. If desired parameters can be rounded up.
*/
-static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
+static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach,
+ struct fb_var_screeninfo *var)
{
struct pxafb_mode_info *mode = NULL;
struct pxafb_mode_info *modelist = mach->modes;
unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
unsigned int i;
- for (i = 0 ; i < mach->num_modes ; i++) {
- if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
- modelist[i].xres < best_x && modelist[i].yres < best_y &&
- modelist[i].bpp >= var->bits_per_pixel ) {
+ for (i = 0; i < mach->num_modes; i++) {
+ if (modelist[i].xres >= var->xres &&
+ modelist[i].yres >= var->yres &&
+ modelist[i].xres < best_x &&
+ modelist[i].yres < best_y &&
+ modelist[i].bpp >= var->bits_per_pixel) {
best_x = modelist[i].xres;
best_y = modelist[i].yres;
mode = &modelist[i];
@@ -257,7 +275,8 @@ static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struc
return mode;
}
-static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
+static void pxafb_setmode(struct fb_var_screeninfo *var,
+ struct pxafb_mode_info *mode)
{
var->xres = mode->xres;
var->yres = mode->yres;
@@ -315,19 +334,20 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->yres_virtual =
max(var->yres_virtual, var->yres);
- /*
+ /*
* Setup the RGB parameters for this display.
*
* The pixel packing format is described on page 7-11 of the
* PXA2XX Developer's Manual.
- */
+ */
if (var->bits_per_pixel == 16) {
var->red.offset = 11; var->red.length = 5;
var->green.offset = 5; var->green.length = 6;
var->blue.offset = 0; var->blue.length = 5;
var->transp.offset = var->transp.length = 0;
} else {
- var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
+ var->red.offset = var->green.offset = 0;
+ var->blue.offset = var->transp.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
@@ -345,8 +365,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static inline void pxafb_set_truecolor(u_int is_true_color)
{
- pr_debug("pxafb: true_color = %d\n", is_true_color);
- // do your machine-specific setup if needed
+ /* do your machine-specific setup if needed */
}
/*
@@ -357,9 +376,6 @@ static int pxafb_set_par(struct fb_info *info)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
struct fb_var_screeninfo *var = &info->var;
- unsigned long palette_mem_size;
-
- pr_debug("pxafb: set_par\n");
if (var->bits_per_pixel == 16)
fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
@@ -379,17 +395,10 @@ static int pxafb_set_par(struct fb_info *info)
if (var->bits_per_pixel == 16)
fbi->palette_size = 0;
else
- fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
-
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- palette_mem_size = fbi->palette_size * sizeof(u16);
- else
- palette_mem_size = fbi->palette_size * sizeof(u32);
-
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
+ fbi->palette_size = var->bits_per_pixel == 1 ?
+ 4 : 1 << var->bits_per_pixel;
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+ fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0];
/*
* Set (any) board control register to handle new color depth
@@ -407,36 +416,6 @@ static int pxafb_set_par(struct fb_info *info)
}
/*
- * Formal definition of the VESA spec:
- * On
- * This refers to the state of the display when it is in full operation
- * Stand-By
- * This defines an optional operating state of minimal power reduction with
- * the shortest recovery time
- * Suspend
- * This refers to a level of power management in which substantial power
- * reduction is achieved by the display. The display can have a longer
- * recovery time from this state than from the Stand-by state
- * Off
- * This indicates that the display is consuming the lowest level of power
- * and is non-operational. Recovery from this state may optionally require
- * the user to manually power on the monitor
- *
- * Now, the fbdev driver adds an additional state, (blank), where they
- * turn off the video (maybe by colormap tricks), but don't mess with the
- * video itself: think of it semantically between on and Stand-By.
- *
- * So here's what we should do in our fbdev blank routine:
- *
- * VESA_NO_BLANKING (mode 0) Video on, front/back light on
- * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off
- * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off
- * VESA_POWERDOWN (mode 3) Video off, front/back light off
- *
- * This will match the matrox implementation.
- */
-
-/*
* pxafb_blank():
* Blank the display by setting all palette values to zero. Note, the
* 16 bpp mode does not really use the palette, so this will not
@@ -447,8 +426,6 @@ static int pxafb_blank(int blank, struct fb_info *info)
struct pxafb_info *fbi = (struct pxafb_info *)info;
int i;
- pr_debug("pxafb: blank=%d\n", blank);
-
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_VSYNC_SUSPEND:
@@ -460,11 +437,11 @@ static int pxafb_blank(int blank, struct fb_info *info)
pxafb_setpalettereg(i, 0, 0, 0, 0, info);
pxafb_schedule_work(fbi, C_DISABLE);
- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
break;
case FB_BLANK_UNBLANK:
- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&fbi->fb.cmap, info);
@@ -480,7 +457,7 @@ static int pxafb_mmap(struct fb_info *info,
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
- vma->vm_pgoff += 1;
+ vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
@@ -529,7 +506,8 @@ static struct fb_ops pxafb_ops = {
*
* Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
*/
-static inline unsigned int get_pcd(struct pxafb_info *fbi, unsigned int pixclock)
+static inline unsigned int get_pcd(struct pxafb_info *fbi,
+ unsigned int pixclock)
{
unsigned long long pcd;
@@ -555,7 +533,7 @@ static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd)
unsigned long htime;
if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
- fbi->hsync_time=0;
+ fbi->hsync_time = 0;
return;
}
@@ -576,71 +554,231 @@ unsigned long pxafb_get_hsync_time(struct device *dev)
}
EXPORT_SYMBOL(pxafb_get_hsync_time);
-/*
- * pxafb_activate_var():
- * Configures LCD Controller based on entries in var parameter. Settings are
- * only written to the controller if changes were made.
- */
-static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
+static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
+ unsigned int offset, size_t size)
{
- struct pxafb_lcd_reg new_regs;
- u_long flags;
- u_int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+ struct pxafb_dma_descriptor *dma_desc, *pal_desc;
+ unsigned int dma_desc_off, pal_desc_off;
- pr_debug("pxafb: Configuring PXA LCD\n");
+ if (dma < 0 || dma >= DMA_MAX)
+ return -EINVAL;
- pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
- var->xres, var->hsync_len,
- var->left_margin, var->right_margin);
- pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
- var->yres, var->vsync_len,
- var->upper_margin, var->lower_margin);
- pr_debug("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
+ dma_desc = &fbi->dma_buff->dma_desc[dma];
+ dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]);
-#if DEBUG_VAR
- if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d\n",
- fbi->fb.fix.id, var->xres);
- switch(var->bits_per_pixel) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- break;
- default:
- printk(KERN_ERR "%s: invalid bit depth %d\n",
- fbi->fb.fix.id, var->bits_per_pixel);
- break;
+ dma_desc->fsadr = fbi->screen_dma + offset;
+ dma_desc->fidr = 0;
+ dma_desc->ldcmd = size;
+
+ if (pal < 0 || pal >= PAL_MAX) {
+ dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
+ } else {
+ pal_desc = &fbi->dma_buff->pal_desc[dma];
+ pal_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[pal]);
+
+ pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE;
+ pal_desc->fidr = 0;
+
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ pal_desc->ldcmd = fbi->palette_size * sizeof(u16);
+ else
+ pal_desc->ldcmd = fbi->palette_size * sizeof(u32);
+
+ pal_desc->ldcmd |= LDCMD_PAL;
+
+ /* flip back and forth between palette and frame buffer */
+ pal_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ dma_desc->fdadr = fbi->dma_buff_phys + pal_desc_off;
+ fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
}
- if (var->hsync_len < 1 || var->hsync_len > 64)
- printk(KERN_ERR "%s: invalid hsync_len %d\n",
- fbi->fb.fix.id, var->hsync_len);
- if (var->left_margin < 1 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d\n",
- fbi->fb.fix.id, var->left_margin);
- if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d\n",
- fbi->fb.fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 1024)
- printk(KERN_ERR "%s: invalid yres %d\n",
- fbi->fb.fix.id, var->yres);
- if (var->vsync_len < 1 || var->vsync_len > 64)
- printk(KERN_ERR "%s: invalid vsync_len %d\n",
- fbi->fb.fix.id, var->vsync_len);
- if (var->upper_margin < 0 || var->upper_margin > 255)
- printk(KERN_ERR "%s: invalid upper_margin %d\n",
- fbi->fb.fix.id, var->upper_margin);
- if (var->lower_margin < 0 || var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d\n",
- fbi->fb.fix.id, var->lower_margin);
-#endif
- new_regs.lccr0 = fbi->lccr0 |
- (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
- LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
+ return 0;
+}
+
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+static int setup_smart_dma(struct pxafb_info *fbi)
+{
+ struct pxafb_dma_descriptor *dma_desc;
+ unsigned long dma_desc_off, cmd_buff_off;
+
+ dma_desc = &fbi->dma_buff->dma_desc[DMA_CMD];
+ dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[DMA_CMD]);
+ cmd_buff_off = offsetof(struct pxafb_dma_buff, cmd_buff);
+
+ dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ dma_desc->fsadr = fbi->dma_buff_phys + cmd_buff_off;
+ dma_desc->fidr = 0;
+ dma_desc->ldcmd = fbi->n_smart_cmds * sizeof(uint16_t);
+
+ fbi->fdadr[DMA_CMD] = dma_desc->fdadr;
+ return 0;
+}
+
+int pxafb_smart_flush(struct fb_info *info)
+{
+ struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
+ uint32_t prsr;
+ int ret = 0;
+
+ /* disable controller until all registers are set up */
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+
+ /* 1. make it an even number of commands to align on 32-bit boundary
+ * 2. add the interrupt command to the end of the chain so we can
+ * keep track of the end of the transfer
+ */
+
+ while (fbi->n_smart_cmds & 1)
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_NOOP;
+
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_INTERRUPT;
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_WAIT_FOR_VSYNC;
+ setup_smart_dma(fbi);
+
+ /* continue to execute next command */
+ prsr = lcd_readl(fbi, PRSR) | PRSR_ST_OK | PRSR_CON_NT;
+ lcd_writel(fbi, PRSR, prsr);
+
+ /* stop the processor in case it executed "wait for sync" cmd */
+ lcd_writel(fbi, CMDCR, 0x0001);
+
+ /* don't send interrupts for fifo underruns on channel 6 */
+ lcd_writel(fbi, LCCR5, LCCR5_IUM(6));
+
+ lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
+ lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
+ lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+ lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
+ lcd_writel(fbi, FDADR6, fbi->fdadr[6]);
+
+ /* begin sending */
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
+
+ if (wait_for_completion_timeout(&fbi->command_done, HZ/2) == 0) {
+ pr_warning("%s: timeout waiting for command done\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ /* quick disable */
+ prsr = lcd_readl(fbi, PRSR) & ~(PRSR_ST_OK | PRSR_CON_NT);
+ lcd_writel(fbi, PRSR, prsr);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+ lcd_writel(fbi, FDADR6, 0);
+ fbi->n_smart_cmds = 0;
+ return ret;
+}
+
+int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
+{
+ int i;
+ struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
+
+ /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */
+ for (i = 0; i < n_cmds; i++) {
+ if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8)
+ pxafb_smart_flush(info);
+
+ fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds++;
+ }
+
+ return 0;
+}
+
+static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk)
+{
+ unsigned int t = (time_ns * (lcd_clk / 1000000) / 1000);
+ return (t == 0) ? 1 : t;
+}
+
+static void setup_smart_timing(struct pxafb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+ struct pxafb_mode_info *mode = &inf->modes[0];
+ unsigned long lclk = clk_get_rate(fbi->clk);
+ unsigned t1, t2, t3, t4;
+
+ t1 = max(mode->a0csrd_set_hld, mode->a0cswr_set_hld);
+ t2 = max(mode->rd_pulse_width, mode->wr_pulse_width);
+ t3 = mode->op_hold_time;
+ t4 = mode->cmd_inh_time;
+
+ fbi->reg_lccr1 =
+ LCCR1_DisWdth(var->xres) |
+ LCCR1_BegLnDel(__smart_timing(t1, lclk)) |
+ LCCR1_EndLnDel(__smart_timing(t2, lclk)) |
+ LCCR1_HorSnchWdth(__smart_timing(t3, lclk));
+
+ fbi->reg_lccr2 = LCCR2_DisHght(var->yres);
+ fbi->reg_lccr3 = LCCR3_PixClkDiv(__smart_timing(t4, lclk));
+
+ /* FIXME: make this configurable */
+ fbi->reg_cmdcr = 1;
+}
+
+static int pxafb_smart_thread(void *arg)
+{
+ struct pxafb_info *fbi = arg;
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+
+ if (!fbi || !inf->smart_update) {
+ pr_err("%s: not properly initialized, thread terminated\n",
+ __func__);
+ return -EINVAL;
+ }
- new_regs.lccr1 =
+ pr_debug("%s(): task starting\n", __func__);
+
+ set_freezable();
+ while (!kthread_should_stop()) {
+
+ if (try_to_freeze())
+ continue;
+
+ if (fbi->state == C_ENABLE) {
+ inf->smart_update(&fbi->fb);
+ complete(&fbi->refresh_done);
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(30 * HZ / 1000);
+ }
+
+ pr_debug("%s(): task ending\n", __func__);
+ return 0;
+}
+
+static int pxafb_smart_init(struct pxafb_info *fbi)
+{
+ fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi,
+ "lcd_refresh");
+ if (IS_ERR(fbi->smart_thread)) {
+ printk(KERN_ERR "%s: unable to create kernel thread\n",
+ __func__);
+ return PTR_ERR(fbi->smart_thread);
+ }
+ return 0;
+}
+#else
+int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
+{
+ return 0;
+}
+
+int pxafb_smart_flush(struct fb_info *info)
+{
+ return 0;
+}
+#endif /* CONFIG_FB_SMART_PANEL */
+
+static void setup_parallel_timing(struct pxafb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ unsigned int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+
+ fbi->reg_lccr1 =
LCCR1_DisWdth(var->xres) +
LCCR1_HorSnchWdth(var->hsync_len) +
LCCR1_BegLnDel(var->left_margin) +
@@ -654,110 +792,118 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
lines_per_panel /= 2;
- new_regs.lccr2 =
+ fbi->reg_lccr2 =
LCCR2_DisHght(lines_per_panel) +
LCCR2_VrtSnchWdth(var->vsync_len) +
LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin);
- new_regs.lccr3 = fbi->lccr3 |
- pxafb_bpp_to_lccr3(var) |
- (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
- (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+ fbi->reg_lccr3 = fbi->lccr3 |
+ (var->sync & FB_SYNC_HOR_HIGH_ACT ?
+ LCCR3_HorSnchH : LCCR3_HorSnchL) |
+ (var->sync & FB_SYNC_VERT_HIGH_ACT ?
+ LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+
+ if (pcd) {
+ fbi->reg_lccr3 |= LCCR3_PixClkDiv(pcd);
+ set_hsync_time(fbi, pcd);
+ }
+}
- if (pcd)
- new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+/*
+ * pxafb_activate_var():
+ * Configures LCD Controller based on entries in var parameter.
+ * Settings are only written to the controller if changes were made.
+ */
+static int pxafb_activate_var(struct fb_var_screeninfo *var,
+ struct pxafb_info *fbi)
+{
+ u_long flags;
+ size_t nbytes;
- pr_debug("nlccr0 = 0x%08x\n", new_regs.lccr0);
- pr_debug("nlccr1 = 0x%08x\n", new_regs.lccr1);
- pr_debug("nlccr2 = 0x%08x\n", new_regs.lccr2);
- pr_debug("nlccr3 = 0x%08x\n", new_regs.lccr3);
+#if DEBUG_VAR
+ if (!(fbi->lccr0 & LCCR0_LCDT)) {
+ if (var->xres < 16 || var->xres > 1024)
+ printk(KERN_ERR "%s: invalid xres %d\n",
+ fbi->fb.fix.id, var->xres);
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ printk(KERN_ERR "%s: invalid bit depth %d\n",
+ fbi->fb.fix.id, var->bits_per_pixel);
+ break;
+ }
+ if (var->hsync_len < 1 || var->hsync_len > 64)
+ printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ fbi->fb.fix.id, var->hsync_len);
+ if (var->left_margin < 1 || var->left_margin > 255)
+ printk(KERN_ERR "%s: invalid left_margin %d\n",
+ fbi->fb.fix.id, var->left_margin);
+ if (var->right_margin < 1 || var->right_margin > 255)
+ printk(KERN_ERR "%s: invalid right_margin %d\n",
+ fbi->fb.fix.id, var->right_margin);
+ if (var->yres < 1 || var->yres > 1024)
+ printk(KERN_ERR "%s: invalid yres %d\n",
+ fbi->fb.fix.id, var->yres);
+ if (var->vsync_len < 1 || var->vsync_len > 64)
+ printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ fbi->fb.fix.id, var->vsync_len);
+ if (var->upper_margin < 0 || var->upper_margin > 255)
+ printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ fbi->fb.fix.id, var->upper_margin);
+ if (var->lower_margin < 0 || var->lower_margin > 255)
+ printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ fbi->fb.fix.id, var->lower_margin);
+ }
+#endif
/* Update shadow copy atomically */
local_irq_save(flags);
- /* setup dma descriptors */
- fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
- fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
- fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
-
- fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
- fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
- fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
-
-#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length)
-
- /* populate descriptors */
- fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
- fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
- fbi->dmadesc_fblow_cpu->fidr = 0;
- fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (fbi->lccr0 & LCCR0_LCDT)
+ setup_smart_timing(fbi, var);
+ else
+#endif
+ setup_parallel_timing(fbi, var);
- fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
+ fbi->reg_lccr0 = fbi->lccr0 |
+ (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+ LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
- fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
- fbi->dmadesc_fbhigh_cpu->fidr = 0;
- fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
+ fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
- fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
- fbi->dmadesc_palette_cpu->fidr = 0;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
- sizeof(u16);
- else
- fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
- sizeof(u32);
- fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
+ nbytes = var->yres * fbi->fb.fix.line_length;
- if (var->bits_per_pixel == 16) {
- /* palette shouldn't be loaded in true-color mode */
- fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
- fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
- /* init it to something, even though we won't be using it */
- fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
- } else {
- fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
- fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
- fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
+ if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) {
+ nbytes = nbytes / 2;
+ setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes);
}
-#if 0
- pr_debug("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
- pr_debug("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
- pr_debug("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
- pr_debug("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
- pr_debug("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
- pr_debug("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
-
- pr_debug("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
- pr_debug("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
- pr_debug("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
-
- pr_debug("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
- pr_debug("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
- pr_debug("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
-
- pr_debug("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
- pr_debug("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
- pr_debug("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
-#endif
+ if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT))
+ setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes);
+ else
+ setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes);
- fbi->reg_lccr0 = new_regs.lccr0;
- fbi->reg_lccr1 = new_regs.lccr1;
- fbi->reg_lccr2 = new_regs.lccr2;
- fbi->reg_lccr3 = new_regs.lccr3;
- fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK);
+ fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK;
fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
- set_hsync_time(fbi, pcd);
local_irq_restore(flags);
/*
* Only update the registers if the controller is enabled
* and something has changed.
*/
- if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
- (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
- (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1))
+ if ((lcd_readl(fbi, LCCR0) != fbi->reg_lccr0) ||
+ (lcd_readl(fbi, LCCR1) != fbi->reg_lccr1) ||
+ (lcd_readl(fbi, LCCR2) != fbi->reg_lccr2) ||
+ (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
+ (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
+ (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
pxafb_schedule_work(fbi, C_REENABLE);
return 0;
@@ -773,8 +919,8 @@ static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
{
pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff");
- if (pxafb_backlight_power)
- pxafb_backlight_power(on);
+ if (pxafb_backlight_power)
+ pxafb_backlight_power(on);
}
static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
@@ -788,11 +934,11 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
static void pxafb_setup_gpio(struct pxafb_info *fbi)
{
int gpio, ldd_bits;
- unsigned int lccr0 = fbi->lccr0;
+ unsigned int lccr0 = fbi->lccr0;
/*
* setup is based on type of panel supported
- */
+ */
/* 4 bit interface */
if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
@@ -801,21 +947,25 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
ldd_bits = 4;
/* 8 bit interface */
- else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
- ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
- (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
+ else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
+ (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+ ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+ (lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+ (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
ldd_bits = 8;
/* 16 bit interface */
else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
+ (lccr0 & LCCR0_PAS) == LCCR0_Act))
ldd_bits = 16;
else {
- printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+ printk(KERN_ERR "pxafb_setup_gpio: unable to determine "
+ "bits per pixel\n");
return;
- }
+ }
for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
@@ -828,8 +978,8 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
static void pxafb_enable_controller(struct pxafb_info *fbi)
{
pr_debug("pxafb: Enabling LCD controller\n");
- pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
- pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+ pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr[0]);
+ pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr[1]);
pr_debug("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
pr_debug("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
pr_debug("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
@@ -838,40 +988,40 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
/* enable LCD controller clock */
clk_enable(fbi->clk);
+ if (fbi->lccr0 & LCCR0_LCDT)
+ return;
+
/* Sequence from 11.7.10 */
- LCCR3 = fbi->reg_lccr3;
- LCCR2 = fbi->reg_lccr2;
- LCCR1 = fbi->reg_lccr1;
- LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
-
- FDADR0 = fbi->fdadr0;
- FDADR1 = fbi->fdadr1;
- LCCR0 |= LCCR0_ENB;
-
- pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
- pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
- pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
- pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1);
- pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2);
- pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3);
- pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4);
+ lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+ lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
+ lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+
+ lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
+ lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
}
static void pxafb_disable_controller(struct pxafb_info *fbi)
{
- DECLARE_WAITQUEUE(wait, current);
+ uint32_t lccr0;
- pr_debug("pxafb: disabling LCD controller\n");
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (fbi->lccr0 & LCCR0_LCDT) {
+ wait_for_completion_timeout(&fbi->refresh_done,
+ 200 * HZ / 1000);
+ return;
+ }
+#endif
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&fbi->ctrlr_wait, &wait);
+ /* Clear LCD Status Register */
+ lcd_writel(fbi, LCSR, 0xffffffff);
- LCSR = 0xffffffff; /* Clear LCD Status Register */
- LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
- LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
+ lccr0 = lcd_readl(fbi, LCCR0) & ~LCCR0_LDM;
+ lcd_writel(fbi, LCCR0, lccr0);
+ lcd_writel(fbi, LCCR0, lccr0 | LCCR0_DIS);
- schedule_timeout(200 * HZ / 1000);
- remove_wait_queue(&fbi->ctrlr_wait, &wait);
+ wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000);
/* disable LCD controller clock */
clk_disable(fbi->clk);
@@ -883,14 +1033,20 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
{
struct pxafb_info *fbi = dev_id;
- unsigned int lcsr = LCSR;
+ unsigned int lccr0, lcsr = lcd_readl(fbi, LCSR);
if (lcsr & LCSR_LDD) {
- LCCR0 |= LCCR0_LDM;
- wake_up(&fbi->ctrlr_wait);
+ lccr0 = lcd_readl(fbi, LCCR0);
+ lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM);
+ complete(&fbi->disable_done);
}
- LCSR = lcsr;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (lcsr & LCSR_CMD_INT)
+ complete(&fbi->command_done);
+#endif
+
+ lcd_writel(fbi, LCSR, lcsr);
return IRQ_HANDLED;
}
@@ -921,7 +1077,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
*/
if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
fbi->state = state;
- //TODO __pxafb_lcd_power(fbi, 0);
+ /* TODO __pxafb_lcd_power(fbi, 0); */
pxafb_disable_controller(fbi);
}
break;
@@ -948,7 +1104,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
if (old_state == C_DISABLE_CLKCHANGE) {
fbi->state = C_ENABLE;
pxafb_enable_controller(fbi);
- //TODO __pxafb_lcd_power(fbi, 1);
+ /* TODO __pxafb_lcd_power(fbi, 1); */
}
break;
@@ -1019,7 +1175,7 @@ static int
pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
{
struct pxafb_info *fbi = TO_INF(nb, freq_transition);
- //TODO struct cpufreq_freqs *f = data;
+ /* TODO struct cpufreq_freqs *f = data; */
u_int pcd;
switch (val) {
@@ -1030,7 +1186,8 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
case CPUFREQ_POSTCHANGE:
pcd = get_pcd(fbi, fbi->fb.var.pixclock);
set_hsync_time(fbi, pcd);
- fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) |
+ LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break;
}
@@ -1050,18 +1207,8 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
pr_debug("min dma period: %d ps, "
"new clock %d kHz\n", pxafb_display_dma_period(var),
policy->max);
- // TODO: fill in min/max values
- break;
-#if 0
- case CPUFREQ_NOTIFY:
- printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__);
- do {} while(0);
- /* todo: panic if min/max values aren't fulfilled
- * [can't really happen unless there's a bug in the
- * CPU policy verification process *
- */
+ /* TODO: fill in min/max values */
break;
-#endif
}
return 0;
}
@@ -1102,21 +1249,21 @@ static int pxafb_resume(struct platform_device *dev)
*/
static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
{
- u_long palette_mem_size;
-
/*
* We reserve one page for the palette, plus the size
* of the framebuffer.
*/
- fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+ fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
&fbi->map_dma, GFP_KERNEL);
if (fbi->map_cpu) {
/* prevent initial garbage on screen */
memset(fbi->map_cpu, 0, fbi->map_size);
- fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
- fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+ fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
/*
* FIXME: this is actually the wrong thing to place in
* smem_start. But fbdev suffers from the problem that
@@ -1126,27 +1273,86 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
fbi->fb.fix.smem_start = fbi->screen_dma;
fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- palette_mem_size = fbi->palette_size * sizeof(u16);
- else
- palette_mem_size = fbi->palette_size * sizeof(u32);
+ fbi->dma_buff = (void *) fbi->map_cpu;
+ fbi->dma_buff_phys = fbi->map_dma;
+ fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
-
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
+ fbi->n_smart_cmds = 0;
+#endif
}
return fbi->map_cpu ? 0 : -ENOMEM;
}
+static void pxafb_decode_mode_info(struct pxafb_info *fbi,
+ struct pxafb_mode_info *modes,
+ unsigned int num_modes)
+{
+ unsigned int i, smemlen;
+
+ pxafb_setmode(&fbi->fb.var, &modes[0]);
+
+ for (i = 0; i < num_modes; i++) {
+ smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8;
+ if (smemlen > fbi->fb.fix.smem_len)
+ fbi->fb.fix.smem_len = smemlen;
+ }
+}
+
+static int pxafb_decode_mach_info(struct pxafb_info *fbi,
+ struct pxafb_mach_info *inf)
+{
+ unsigned int lcd_conn = inf->lcd_conn;
+
+ fbi->cmap_inverse = inf->cmap_inverse;
+ fbi->cmap_static = inf->cmap_static;
+
+ switch (lcd_conn & 0xf) {
+ case LCD_TYPE_MONO_STN:
+ fbi->lccr0 = LCCR0_CMS;
+ break;
+ case LCD_TYPE_MONO_DSTN:
+ fbi->lccr0 = LCCR0_CMS | LCCR0_SDS;
+ break;
+ case LCD_TYPE_COLOR_STN:
+ fbi->lccr0 = 0;
+ break;
+ case LCD_TYPE_COLOR_DSTN:
+ fbi->lccr0 = LCCR0_SDS;
+ break;
+ case LCD_TYPE_COLOR_TFT:
+ fbi->lccr0 = LCCR0_PAS;
+ break;
+ case LCD_TYPE_SMART_PANEL:
+ fbi->lccr0 = LCCR0_LCDT | LCCR0_PAS;
+ break;
+ default:
+ /* fall back to backward compatibility way */
+ fbi->lccr0 = inf->lccr0;
+ fbi->lccr3 = inf->lccr3;
+ fbi->lccr4 = inf->lccr4;
+ return -EINVAL;
+ }
+
+ if (lcd_conn == LCD_MONO_STN_8BPP)
+ fbi->lccr0 |= LCCR0_DPD;
+
+ fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff);
+ fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0;
+ fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0;
+
+ pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
+ return 0;
+}
+
static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
{
struct pxafb_info *fbi;
void *addr;
struct pxafb_mach_info *inf = dev->platform_data;
struct pxafb_mode_info *mode = inf->modes;
- int i, smemlen;
/* Alloc the pxafb_info and pseudo_palette in one step */
fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1186,187 +1392,233 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
addr = addr + sizeof(struct pxafb_info);
fbi->fb.pseudo_palette = addr;
- pxafb_setmode(&fbi->fb.var, mode);
+ fbi->state = C_STARTUP;
+ fbi->task_state = (u_char)-1;
- fbi->cmap_inverse = inf->cmap_inverse;
- fbi->cmap_static = inf->cmap_static;
-
- fbi->lccr0 = inf->lccr0;
- fbi->lccr3 = inf->lccr3;
- fbi->lccr4 = inf->lccr4;
- fbi->state = C_STARTUP;
- fbi->task_state = (u_char)-1;
-
- for (i = 0; i < inf->num_modes; i++) {
- smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
- if (smemlen > fbi->fb.fix.smem_len)
- fbi->fb.fix.smem_len = smemlen;
- }
+ pxafb_decode_mach_info(fbi, inf);
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, pxafb_task);
init_MUTEX(&fbi->ctrlr_sem);
+ init_completion(&fbi->disable_done);
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ init_completion(&fbi->command_done);
+ init_completion(&fbi->refresh_done);
+#endif
return fbi;
}
#ifdef CONFIG_FB_PXA_PARAMETERS
-static int __init pxafb_parse_options(struct device *dev, char *options)
+static int __init parse_opt_mode(struct device *dev, const char *this_opt)
+{
+ struct pxafb_mach_info *inf = dev->platform_data;
+
+ const char *name = this_opt+5;
+ unsigned int namelen = strlen(name);
+ int res_specified = 0, bpp_specified = 0;
+ unsigned int xres = 0, yres = 0, bpp = 0;
+ int yres_specified = 0;
+ int i;
+ for (i = namelen-1; i >= 0; i--) {
+ switch (name[i]) {
+ case '-':
+ namelen = i;
+ if (!bpp_specified && !yres_specified) {
+ bpp = simple_strtoul(&name[i+1], NULL, 0);
+ bpp_specified = 1;
+ } else
+ goto done;
+ break;
+ case 'x':
+ if (!yres_specified) {
+ yres = simple_strtoul(&name[i+1], NULL, 0);
+ yres_specified = 1;
+ } else
+ goto done;
+ break;
+ case '0' ... '9':
+ break;
+ default:
+ goto done;
+ }
+ }
+ if (i < 0 && yres_specified) {
+ xres = simple_strtoul(name, NULL, 0);
+ res_specified = 1;
+ }
+done:
+ if (res_specified) {
+ dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
+ inf->modes[0].xres = xres; inf->modes[0].yres = yres;
+ }
+ if (bpp_specified)
+ switch (bpp) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ inf->modes[0].bpp = bpp;
+ dev_info(dev, "overriding bit depth: %d\n", bpp);
+ break;
+ default:
+ dev_err(dev, "Depth %d is not valid\n", bpp);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __init parse_opt(struct device *dev, char *this_opt)
{
struct pxafb_mach_info *inf = dev->platform_data;
+ struct pxafb_mode_info *mode = &inf->modes[0];
+ char s[64];
+
+ s[0] = '\0';
+
+ if (!strncmp(this_opt, "mode:", 5)) {
+ return parse_opt_mode(dev, this_opt);
+ } else if (!strncmp(this_opt, "pixclock:", 9)) {
+ mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "pixclock: %ld\n", mode->pixclock);
+ } else if (!strncmp(this_opt, "left:", 5)) {
+ mode->left_margin = simple_strtoul(this_opt+5, NULL, 0);
+ sprintf(s, "left: %u\n", mode->left_margin);
+ } else if (!strncmp(this_opt, "right:", 6)) {
+ mode->right_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "right: %u\n", mode->right_margin);
+ } else if (!strncmp(this_opt, "upper:", 6)) {
+ mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "upper: %u\n", mode->upper_margin);
+ } else if (!strncmp(this_opt, "lower:", 6)) {
+ mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "lower: %u\n", mode->lower_margin);
+ } else if (!strncmp(this_opt, "hsynclen:", 9)) {
+ mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "hsynclen: %u\n", mode->hsync_len);
+ } else if (!strncmp(this_opt, "vsynclen:", 9)) {
+ mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "vsynclen: %u\n", mode->vsync_len);
+ } else if (!strncmp(this_opt, "hsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ sprintf(s, "hsync: Active Low\n");
+ mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ } else {
+ sprintf(s, "hsync: Active High\n");
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ }
+ } else if (!strncmp(this_opt, "vsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ sprintf(s, "vsync: Active Low\n");
+ mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ } else {
+ sprintf(s, "vsync: Active High\n");
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+ } else if (!strncmp(this_opt, "dpc:", 4)) {
+ if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
+ sprintf(s, "double pixel clock: false\n");
+ inf->lccr3 &= ~LCCR3_DPC;
+ } else {
+ sprintf(s, "double pixel clock: true\n");
+ inf->lccr3 |= LCCR3_DPC;
+ }
+ } else if (!strncmp(this_opt, "outputen:", 9)) {
+ if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
+ sprintf(s, "output enable: active low\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
+ } else {
+ sprintf(s, "output enable: active high\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
+ }
+ } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+ if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
+ sprintf(s, "pixel clock polarity: falling edge\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
+ } else {
+ sprintf(s, "pixel clock polarity: rising edge\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
+ }
+ } else if (!strncmp(this_opt, "color", 5)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
+ } else if (!strncmp(this_opt, "mono", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
+ } else if (!strncmp(this_opt, "active", 6)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
+ } else if (!strncmp(this_opt, "passive", 7)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
+ } else if (!strncmp(this_opt, "single", 6)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
+ } else if (!strncmp(this_opt, "dual", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
+ } else if (!strncmp(this_opt, "4pix", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
+ } else if (!strncmp(this_opt, "8pix", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
+ } else {
+ dev_err(dev, "unknown option: %s\n", this_opt);
+ return -EINVAL;
+ }
+
+ if (s[0] != '\0')
+ dev_info(dev, "override %s", s);
+
+ return 0;
+}
+
+static int __init pxafb_parse_options(struct device *dev, char *options)
+{
char *this_opt;
+ int ret;
- if (!options || !*options)
- return 0;
+ if (!options || !*options)
+ return 0;
dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
/* could be made table driven or similar?... */
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!strncmp(this_opt, "mode:", 5)) {
- const char *name = this_opt+5;
- unsigned int namelen = strlen(name);
- int res_specified = 0, bpp_specified = 0;
- unsigned int xres = 0, yres = 0, bpp = 0;
- int yres_specified = 0;
- int i;
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '-':
- namelen = i;
- if (!bpp_specified && !yres_specified) {
- bpp = simple_strtoul(&name[i+1], NULL, 0);
- bpp_specified = 1;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified) {
- yres = simple_strtoul(&name[i+1], NULL, 0);
- yres_specified = 1;
- } else
- goto done;
- break;
- case '0' ... '9':
- break;
- default:
- goto done;
- }
- }
- if (i < 0 && yres_specified) {
- xres = simple_strtoul(name, NULL, 0);
- res_specified = 1;
- }
- done:
- if (res_specified) {
- dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
- inf->modes[0].xres = xres; inf->modes[0].yres = yres;
- }
- if (bpp_specified)
- switch (bpp) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- inf->modes[0].bpp = bpp;
- dev_info(dev, "overriding bit depth: %d\n", bpp);
- break;
- default:
- dev_err(dev, "Depth %d is not valid\n", bpp);
- }
- } else if (!strncmp(this_opt, "pixclock:", 9)) {
- inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock);
- } else if (!strncmp(this_opt, "left:", 5)) {
- inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0);
- dev_info(dev, "override left: %u\n", inf->modes[0].left_margin);
- } else if (!strncmp(this_opt, "right:", 6)) {
- inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override right: %u\n", inf->modes[0].right_margin);
- } else if (!strncmp(this_opt, "upper:", 6)) {
- inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin);
- } else if (!strncmp(this_opt, "lower:", 6)) {
- inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin);
- } else if (!strncmp(this_opt, "hsynclen:", 9)) {
- inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len);
- } else if (!strncmp(this_opt, "vsynclen:", 9)) {
- inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len);
- } else if (!strncmp(this_opt, "hsync:", 6)) {
- if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
- dev_info(dev, "override hsync: Active Low\n");
- inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT;
- } else {
- dev_info(dev, "override hsync: Active High\n");
- inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT;
- }
- } else if (!strncmp(this_opt, "vsync:", 6)) {
- if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
- dev_info(dev, "override vsync: Active Low\n");
- inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT;
- } else {
- dev_info(dev, "override vsync: Active High\n");
- inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT;
- }
- } else if (!strncmp(this_opt, "dpc:", 4)) {
- if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
- dev_info(dev, "override double pixel clock: false\n");
- inf->lccr3 &= ~LCCR3_DPC;
- } else {
- dev_info(dev, "override double pixel clock: true\n");
- inf->lccr3 |= LCCR3_DPC;
- }
- } else if (!strncmp(this_opt, "outputen:", 9)) {
- if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
- dev_info(dev, "override output enable: active low\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
- } else {
- dev_info(dev, "override output enable: active high\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
- }
- } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
- if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
- dev_info(dev, "override pixel clock polarity: falling edge\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
- } else {
- dev_info(dev, "override pixel clock polarity: rising edge\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
- }
- } else if (!strncmp(this_opt, "color", 5)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
- } else if (!strncmp(this_opt, "mono", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
- } else if (!strncmp(this_opt, "active", 6)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
- } else if (!strncmp(this_opt, "passive", 7)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
- } else if (!strncmp(this_opt, "single", 6)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
- } else if (!strncmp(this_opt, "dual", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
- } else if (!strncmp(this_opt, "4pix", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
- } else if (!strncmp(this_opt, "8pix", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
- } else {
- dev_err(dev, "unknown option: %s\n", this_opt);
- return -EINVAL;
- }
- }
- return 0;
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ ret = parse_opt(dev, this_opt);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static char g_options[256] __devinitdata = "";
+#ifndef CONFIG_MODULES
+static int __devinit pxafb_setup_options(void)
+{
+ char *options = NULL;
+
+ if (fb_get_options("pxafb", &options))
+ return -ENODEV;
+
+ if (options)
+ strlcpy(g_options, options, sizeof(g_options));
+
+ return 0;
}
+#else
+#define pxafb_setup_options() (0)
+
+module_param_string(options, g_options, sizeof(g_options), 0);
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
+#endif
+
+#else
+#define pxafb_parse_options(...) (0)
+#define pxafb_setup_options() (0)
#endif
static int __init pxafb_probe(struct platform_device *dev)
{
struct pxafb_info *fbi;
struct pxafb_mach_info *inf;
- int ret;
+ struct resource *r;
+ int irq, ret;
dev_dbg(&dev->dev, "pxafb_probe\n");
@@ -1376,38 +1628,45 @@ static int __init pxafb_probe(struct platform_device *dev)
if (!inf)
goto failed;
-#ifdef CONFIG_FB_PXA_PARAMETERS
ret = pxafb_parse_options(&dev->dev, g_options);
if (ret < 0)
goto failed;
-#endif
#ifdef DEBUG_VAR
- /* Check for various illegal bit-combinations. Currently only
+ /* Check for various illegal bit-combinations. Currently only
* a warning is given. */
- if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
- inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
- if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
- inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
- if (inf->lccr0 & LCCR0_DPD &&
+ if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+ dev_warn(&dev->dev, "machine LCCR0 setting contains "
+ "illegal bits: %08x\n",
+ inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+ if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+ dev_warn(&dev->dev, "machine LCCR3 setting contains "
+ "illegal bits: %08x\n",
+ inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+ if (inf->lccr0 & LCCR0_DPD &&
((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
(inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
(inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
- dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
- " single panel mode\n");
- if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+ dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is "
+ "only valid in passive mono"
+ " single panel mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
(inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
- dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
- if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
- (inf->modes->upper_margin || inf->modes->lower_margin))
- dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
+ dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+ (inf->modes->upper_margin || inf->modes->lower_margin))
+ dev_warn(&dev->dev, "Upper and lower margins must be 0 in "
+ "passive mode\n");
#endif
- dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
- if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
+ dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",
+ inf->modes->xres,
+ inf->modes->yres,
+ inf->modes->bpp);
+ if (inf->modes->xres == 0 ||
+ inf->modes->yres == 0 ||
+ inf->modes->bpp == 0) {
dev_err(&dev->dev, "Invalid resolution or bit depth\n");
ret = -EINVAL;
goto failed;
@@ -1416,26 +1675,62 @@ static int __init pxafb_probe(struct platform_device *dev)
pxafb_lcd_power = inf->pxafb_lcd_power;
fbi = pxafb_init_fbinfo(&dev->dev);
if (!fbi) {
+ /* only reason for pxafb_init_fbinfo to fail is kmalloc */
dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
- ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+ ret = -ENOMEM;
goto failed;
}
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&dev->dev, "no I/O memory resource defined\n");
+ ret = -ENODEV;
+ goto failed;
+ }
+
+ r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
+ if (r == NULL) {
+ dev_err(&dev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto failed;
+ }
+
+ fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
+ if (fbi->mmio_base == NULL) {
+ dev_err(&dev->dev, "failed to map I/O memory\n");
+ ret = -EBUSY;
+ goto failed_free_res;
+ }
+
/* Initialize video memory */
ret = pxafb_map_video_memory(fbi);
if (ret) {
dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
- goto failed;
+ goto failed_free_io;
+ }
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no IRQ defined\n");
+ ret = -ENODEV;
+ goto failed_free_mem;
}
- ret = request_irq(IRQ_LCD, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
if (ret) {
dev_err(&dev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
- goto failed;
+ goto failed_free_mem;
}
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ ret = pxafb_smart_init(fbi);
+ if (ret) {
+ dev_err(&dev->dev, "failed to initialize smartpanel\n");
+ goto failed_free_irq;
+ }
+#endif
/*
* This makes sure that our colour bitfield
* descriptors are correctly initialised.
@@ -1447,19 +1742,18 @@ static int __init pxafb_probe(struct platform_device *dev)
ret = register_framebuffer(&fbi->fb);
if (ret < 0) {
- dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret);
- goto failed;
+ dev_err(&dev->dev,
+ "Failed to register framebuffer device: %d\n", ret);
+ goto failed_free_irq;
}
-#ifdef CONFIG_PM
- // TODO
-#endif
-
#ifdef CONFIG_CPU_FREQ
fbi->freq_transition.notifier_call = pxafb_freq_transition;
fbi->freq_policy.notifier_call = pxafb_freq_policy;
- cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
- cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
+ cpufreq_register_notifier(&fbi->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ cpufreq_register_notifier(&fbi->freq_policy,
+ CPUFREQ_POLICY_NOTIFIER);
#endif
/*
@@ -1469,6 +1763,15 @@ static int __init pxafb_probe(struct platform_device *dev)
return 0;
+failed_free_irq:
+ free_irq(irq, fbi);
+failed_free_res:
+ release_mem_region(r->start, r->end - r->start + 1);
+failed_free_io:
+ iounmap(fbi->mmio_base);
+failed_free_mem:
+ dma_free_writecombine(&dev->dev, fbi->map_size,
+ fbi->map_cpu, fbi->map_dma);
failed:
platform_set_drvdata(dev, NULL);
kfree(fbi);
@@ -1477,40 +1780,18 @@ failed:
static struct platform_driver pxafb_driver = {
.probe = pxafb_probe,
-#ifdef CONFIG_PM
.suspend = pxafb_suspend,
.resume = pxafb_resume,
-#endif
.driver = {
.name = "pxa2xx-fb",
},
};
-#ifndef MODULE
-static int __devinit pxafb_setup(char *options)
-{
-# ifdef CONFIG_FB_PXA_PARAMETERS
- if (options)
- strlcpy(g_options, options, sizeof(g_options));
-# endif
- return 0;
-}
-#else
-# ifdef CONFIG_FB_PXA_PARAMETERS
-module_param_string(options, g_options, sizeof(g_options), 0);
-MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
-# endif
-#endif
-
static int __devinit pxafb_init(void)
{
-#ifndef MODULE
- char *option = NULL;
+ if (pxafb_setup_options())
+ return -EINVAL;
- if (fb_get_options("pxafb", &option))
- return -ENODEV;
- pxafb_setup(option);
-#endif
return platform_driver_register(&pxafb_driver);
}
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index d920b8a14c3..8238dc82642 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -21,14 +21,6 @@
* for more details.
*/
-/* Shadows for LCD controller registers */
-struct pxafb_lcd_reg {
- unsigned int lccr0;
- unsigned int lccr1;
- unsigned int lccr2;
- unsigned int lccr3;
-};
-
/* PXA LCD DMA descriptor */
struct pxafb_dma_descriptor {
unsigned int fdadr;
@@ -37,11 +29,49 @@ struct pxafb_dma_descriptor {
unsigned int ldcmd;
};
+enum {
+ PAL_NONE = -1,
+ PAL_BASE = 0,
+ PAL_OV1 = 1,
+ PAL_OV2 = 2,
+ PAL_MAX,
+};
+
+enum {
+ DMA_BASE = 0,
+ DMA_UPPER = 0,
+ DMA_LOWER = 1,
+ DMA_OV1 = 1,
+ DMA_OV2_Y = 2,
+ DMA_OV2_Cb = 3,
+ DMA_OV2_Cr = 4,
+ DMA_CURSOR = 5,
+ DMA_CMD = 6,
+ DMA_MAX,
+};
+
+/* maximum palette size - 256 entries, each 4 bytes long */
+#define PALETTE_SIZE (256 * 4)
+#define CMD_BUFF_SIZE (1024 * 50)
+
+struct pxafb_dma_buff {
+ unsigned char palette[PAL_MAX * PALETTE_SIZE];
+ uint16_t cmd_buff[CMD_BUFF_SIZE];
+ struct pxafb_dma_descriptor pal_desc[PAL_MAX];
+ struct pxafb_dma_descriptor dma_desc[DMA_MAX];
+};
+
struct pxafb_info {
struct fb_info fb;
struct device *dev;
struct clk *clk;
+ void __iomem *mmio_base;
+
+ struct pxafb_dma_buff *dma_buff;
+ dma_addr_t dma_buff_phys;
+ dma_addr_t fdadr[DMA_MAX];
+
/*
* These are the addresses we mapped
* the framebuffer memory region to.
@@ -55,19 +85,8 @@ struct pxafb_info {
u_char * screen_cpu; /* virtual address of frame buffer */
dma_addr_t screen_dma; /* physical address of frame buffer */
u16 * palette_cpu; /* virtual address of palette memory */
- dma_addr_t palette_dma; /* physical address of palette memory */
u_int palette_size;
-
- /* DMA descriptors */
- struct pxafb_dma_descriptor * dmadesc_fblow_cpu;
- dma_addr_t dmadesc_fblow_dma;
- struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu;
- dma_addr_t dmadesc_fbhigh_dma;
- struct pxafb_dma_descriptor * dmadesc_palette_cpu;
- dma_addr_t dmadesc_palette_dma;
-
- dma_addr_t fdadr0;
- dma_addr_t fdadr1;
+ ssize_t video_offset;
u_int lccr0;
u_int lccr3;
@@ -81,6 +100,7 @@ struct pxafb_info {
u_int reg_lccr2;
u_int reg_lccr3;
u_int reg_lccr4;
+ u_int reg_cmdcr;
unsigned long hsync_time;
@@ -90,6 +110,16 @@ struct pxafb_info {
wait_queue_head_t ctrlr_wait;
struct work_struct task;
+ struct completion disable_done;
+
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ uint16_t *smart_cmds;
+ size_t n_smart_cmds;
+ struct completion command_done;
+ struct completion refresh_done;
+ struct task_struct *smart_thread;
+#endif
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
struct notifier_block freq_policy;
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h
index fe6bdf43380..e6ab7cf08f8 100644
--- a/drivers/w1/w1_log.h
+++ b/drivers/w1/w1_log.h
@@ -30,7 +30,7 @@
# define assert(expr) \
if(unlikely(!(expr))) { \
printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
+ #expr, __FILE__, __func__, __LINE__); \
}
#endif