diff options
Diffstat (limited to 'drivers')
1148 files changed, 62966 insertions, 21519 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 80f0ec91e2cf..59f33fa6af3e 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 e5e394a7e6c0..f65deda72d61 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 000000000000..1264c4b98094 --- /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 000000000000..72b01a46546f --- /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 000000000000..2e9f16c91347 --- /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 000000000000..0a5f6b2114c5 --- /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/acpi/Kconfig b/drivers/acpi/Kconfig index b4f5e8542829..c52fca833268 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -140,6 +140,7 @@ config ACPI_VIDEO tristate "Video" depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL depends on INPUT + select THERMAL help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -151,6 +152,7 @@ config ACPI_VIDEO config ACPI_FAN tristate "Fan" + select THERMAL default y help This driver adds support for ACPI fan devices, allowing user-mode @@ -172,6 +174,7 @@ config ACPI_BAY config ACPI_PROCESSOR tristate "Processor" + select THERMAL default y help This driver installs ACPI as the idle handler for Linux, and uses diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 43a95e5640de..5b73f6a2cd86 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -92,6 +92,7 @@ struct acpi_ac { #ifdef CONFIG_ACPI_PROCFS_POWER static const struct file_operations acpi_ac_fops = { + .owner = THIS_MODULE, .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -195,16 +196,11 @@ static int acpi_ac_add_fs(struct acpi_device *device) } /* 'state' [R] */ - entry = create_proc_entry(ACPI_AC_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_AC_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_ac_fops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_ac_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d5729d5dc190..b1c723f9f58d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -741,15 +741,13 @@ static int acpi_battery_add_fs(struct acpi_device *device) } for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - entry = create_proc_entry(acpi_battery_file[i].name, - acpi_battery_file[i].mode, acpi_device_dir(device)); + entry = proc_create_data(acpi_battery_file[i].name, + acpi_battery_file[i].mode, + acpi_device_dir(device), + &acpi_battery_file[i].ops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_battery_file[i].ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } } return 0; } diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 1fa86811b8ee..d2fc94161848 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -201,6 +201,7 @@ static int is_ejectable_bay(acpi_handle handle) return 0; } +#if 0 /** * eject_removable_drive - try to eject this drive * @dev : the device structure of the drive @@ -225,6 +226,7 @@ int eject_removable_drive(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(eject_removable_drive); +#endif /* 0 */ static int acpi_bay_add_fs(struct bay *bay) { diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2d1955c11833..a6dbcf4d9ef5 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -35,6 +35,7 @@ #ifdef CONFIG_X86 #include <asm/mpspec.h> #endif +#include <linux/pci.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -784,6 +785,7 @@ static int __init acpi_init(void) result = acpi_bus_init(); if (!result) { + pci_mmcfg_late_init(); if (!(pm_flags & PM_APM)) pm_flags |= PM_ACPI; else { diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6c5da83cdb68..1dfec413588c 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -102,6 +102,7 @@ struct acpi_button { }; static const struct file_operations acpi_button_info_fops = { + .owner = THIS_MODULE, .open = acpi_button_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -109,6 +110,7 @@ static const struct file_operations acpi_button_info_fops = { }; static const struct file_operations acpi_button_state_fops = { + .owner = THIS_MODULE, .open = acpi_button_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -207,27 +209,21 @@ static int acpi_button_add_fs(struct acpi_device *device) acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_BUTTON_FILE_INFO, + S_IRUGO, acpi_device_dir(device), + &acpi_button_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_button_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* show lid state [R] */ if (button->type == ACPI_BUTTON_TYPE_LID) { - entry = create_proc_entry(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_BUTTON_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_button_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_button_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } } return 0; diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index f049639bac35..c78078315be9 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,12 +89,16 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, ACPI_FUNCTION_TRACE(ds_create_buffer_field); - /* Get the name_string argument */ - + /* + * Get the name_string argument (name of the new buffer_field) + */ if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { + + /* For create_field, name is the 4th argument */ + arg = acpi_ps_get_arg(op, 3); } else { - /* Create Bit/Byte/Word/Dword field */ + /* For all other create_xXXField operators, name is the 3rd argument */ arg = acpi_ps_get_arg(op, 2); } @@ -107,26 +111,30 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, node = walk_state->deferred_node; status = AE_OK; } else { - /* - * During the load phase, we want to enter the name of the field into - * the namespace. During the execute phase (when we evaluate the size - * operand), we want to lookup the name - */ - if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) { - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; - } else { - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | - ACPI_NS_ERROR_IF_FOUND; + /* Execute flag should always be set when this function is entered */ + + if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { + return_ACPI_STATUS(AE_AML_INTERNAL); } - /* - * Enter the name_string into the namespace - */ + /* Creating new namespace node, should not already exist */ + + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND; + + /* Mark node temporary if we are executing a method */ + + if (walk_state->method_node) { + flags |= ACPI_NS_TEMPORARY; + } + + /* Enter the name_string into the namespace */ + status = acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS1, flags, walk_state, - &(node)); + &node); if (ACPI_FAILURE(status)) { ACPI_ERROR_NAMESPACE(arg->common.value.string, status); return_ACPI_STATUS(status); @@ -136,13 +144,13 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, /* * We could put the returned object (Node) on the object stack for later, * but for now, we will put it in the "op" object that the parser uses, - * so we can get it again at the end of this scope + * so we can get it again at the end of this scope. */ op->common.node = node; /* * If there is no object attached to the node, this node was just created - * and we need to create the field object. Otherwise, this was a lookup + * and we need to create the field object. Otherwise, this was a lookup * of an existing node and we don't want to create the field object again. */ obj_desc = acpi_ns_get_attached_object(node); @@ -164,9 +172,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, } /* - * Remember location in AML stream of the field unit - * opcode and operands -- since the buffer and index - * operands must be evaluated. + * Remember location in AML stream of the field unit opcode and operands -- + * since the buffer and index operands must be evaluated. */ second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = op->named.data; @@ -261,7 +268,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, case AML_INT_NAMEDFIELD_OP: - /* Lookup the name */ + /* Lookup the name, it should already exist */ status = acpi_ns_lookup(walk_state->scope_info, (char *)&arg->named.name, @@ -272,20 +279,23 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, if (ACPI_FAILURE(status)) { ACPI_ERROR_NAMESPACE((char *)&arg->named.name, status); - if (status != AE_ALREADY_EXISTS) { - return_ACPI_STATUS(status); - } - - /* Already exists, ignore error */ + return_ACPI_STATUS(status); } else { arg->common.node = info->field_node; info->field_bit_length = arg->common.value.size; - /* Create and initialize an object for the new Field Node */ - - status = acpi_ex_prep_field_value(info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + /* + * If there is no object attached to the node, this node was + * just created and we need to create the field object. + * Otherwise, this was a lookup of an existing node and we + * don't want to create the field object again. + */ + if (!acpi_ns_get_attached_object + (info->field_node)) { + status = acpi_ex_prep_field_value(info); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } } } @@ -399,9 +409,27 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, union acpi_parse_object *arg = NULL; struct acpi_namespace_node *node; u8 type = 0; + u32 flags; ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); + /* Execute flag should always be set when this function is entered */ + + if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { + if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) { + + /* bank_field Op is deferred, just return OK */ + + return_ACPI_STATUS(AE_OK); + } + + return_ACPI_STATUS(AE_AML_INTERNAL); + } + + /* + * Get the field_list argument for this opcode. This is the start of the + * list of field elements. + */ switch (walk_state->opcode) { case AML_FIELD_OP: arg = acpi_ps_get_arg(op, 2); @@ -422,20 +450,33 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, return_ACPI_STATUS(AE_BAD_PARAMETER); } + if (!arg) { + return_ACPI_STATUS(AE_AML_NO_OPERAND); + } + + /* Creating new namespace node(s), should not already exist */ + + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND; + + /* Mark node(s) temporary if we are executing a method */ + + if (walk_state->method_node) { + flags |= ACPI_NS_TEMPORARY; + } + /* * Walk the list of entries in the field_list */ while (arg) { - - /* Ignore OFFSET and ACCESSAS terms here */ - + /* + * Ignore OFFSET and ACCESSAS terms here; we are only interested in the + * field names in order to enter them into the namespace. + */ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { status = acpi_ns_lookup(walk_state->scope_info, - (char *)&arg->named.name, - type, ACPI_IMODE_LOAD_PASS1, - ACPI_NS_NO_UPSEARCH | - ACPI_NS_DONT_OPEN_SCOPE | - ACPI_NS_ERROR_IF_FOUND, + (char *)&arg->named.name, type, + ACPI_IMODE_LOAD_PASS1, flags, walk_state, &node); if (ACPI_FAILURE(status)) { ACPI_ERROR_NAMESPACE((char *)&arg->named.name, @@ -452,7 +493,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, arg->common.node = node; } - /* Move to next field in the list */ + /* Get the next field element in the list */ arg = arg->common.next; } @@ -466,7 +507,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, * * PARAMETERS: Op - Op containing the Field definition and args * region_node - Object for the containing Operation Region - * ` walk_state - Current method state + * walk_state - Current method state * * RETURN: Status * @@ -513,36 +554,13 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, return_ACPI_STATUS(status); } - /* Third arg is the bank_value */ - - /* TBD: This arg is a term_arg, not a constant, and must be evaluated */ - + /* + * Third arg is the bank_value + * This arg is a term_arg, not a constant + * It will be evaluated later, by acpi_ds_eval_bank_field_operands + */ arg = arg->common.next; - /* Currently, only the following constants are supported */ - - switch (arg->common.aml_opcode) { - case AML_ZERO_OP: - info.bank_value = 0; - break; - - case AML_ONE_OP: - info.bank_value = 1; - break; - - case AML_BYTE_OP: - case AML_WORD_OP: - case AML_DWORD_OP: - case AML_QWORD_OP: - info.bank_value = (u32) arg->common.value.integer; - break; - - default: - info.bank_value = 0; - ACPI_ERROR((AE_INFO, - "Non-constant BankValue for BankField is not implemented")); - } - /* Fourth arg is the field flags */ arg = arg->common.next; @@ -553,8 +571,17 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD; info.region_node = region_node; - status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); + /* + * Use Info.data_register_node to store bank_field Op + * It's safe because data_register_node will never be used when create bank field + * We store aml_start and aml_length in the bank_field Op for late evaluation + * Used in acpi_ex_prep_field_value(Info) + * + * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"? + */ + info.data_register_node = (struct acpi_namespace_node *)op; + status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index af923c388520..610b1ee102b0 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 1cbe61905824..e48a3ea03117 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,7 +42,6 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> #include <acpi/amlcode.h> #include <acpi/acdispat.h> #include <acpi/acinterp.h> @@ -102,7 +101,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) walk_state->opcode, walk_state->aml_offset, NULL); - (void)acpi_ex_enter_interpreter(); + acpi_ex_enter_interpreter(); } #ifdef ACPI_DISASSEMBLER if (ACPI_FAILURE(status)) { @@ -232,9 +231,9 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, * recursive call. */ if (!walk_state || - !obj_desc->method.mutex->mutex.owner_thread || - (walk_state->thread != - obj_desc->method.mutex->mutex.owner_thread)) { + !obj_desc->method.mutex->mutex.thread_id || + (walk_state->thread->thread_id != + obj_desc->method.mutex->mutex.thread_id)) { /* * Acquire the method mutex. This releases the interpreter if we * block (and reacquires it before it returns) @@ -254,8 +253,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, original_sync_level = walk_state->thread->current_sync_level; - obj_desc->method.mutex->mutex.owner_thread = - walk_state->thread; + obj_desc->method.mutex->mutex.thread_id = + walk_state->thread->thread_id; walk_state->thread->current_sync_level = obj_desc->method.sync_level; } else { @@ -535,8 +534,6 @@ void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { - struct acpi_namespace_node *method_node; - acpi_status status; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); @@ -551,34 +548,26 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); - } - /* - * If method is serialized, release the mutex and restore the - * current sync level for this thread - */ - if (method_desc->method.mutex) { + /* + * If method is serialized, release the mutex and restore the + * current sync level for this thread + */ + if (method_desc->method.mutex) { - /* Acquisition Depth handles recursive calls */ + /* Acquisition Depth handles recursive calls */ - method_desc->method.mutex->mutex.acquisition_depth--; - if (!method_desc->method.mutex->mutex.acquisition_depth) { - walk_state->thread->current_sync_level = - method_desc->method.mutex->mutex. - original_sync_level; + method_desc->method.mutex->mutex.acquisition_depth--; + if (!method_desc->method.mutex->mutex.acquisition_depth) { + walk_state->thread->current_sync_level = + method_desc->method.mutex->mutex. + original_sync_level; - acpi_os_release_mutex(method_desc->method.mutex->mutex. - os_mutex); - method_desc->method.mutex->mutex.owner_thread = NULL; + acpi_os_release_mutex(method_desc->method. + mutex->mutex.os_mutex); + method_desc->method.mutex->mutex.thread_id = 0; + } } - } - - if (walk_state) { - /* - * Delete any objects created by this method during execution. - * The method Node is stored in the walk state - */ - method_node = walk_state->method_node; /* * Delete any namespace objects created anywhere within @@ -620,7 +609,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, */ if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED) && (!method_desc->method.mutex)) { - status = acpi_ds_create_method_mutex(method_desc); + (void)acpi_ds_create_method_mutex(method_desc); } /* No more threads, we can free the owner_id */ diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index ba4626e06a5e..13c43eac35db 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 954ac8ce958a..1022e38994c2 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -157,7 +157,9 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, * will remain as named references. This behavior is not described * in the ACPI spec, but it appears to be an oversight. */ - obj_desc = (union acpi_operand_object *)op->common.node; + obj_desc = + ACPI_CAST_PTR(union acpi_operand_object, + op->common.node); status = acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR @@ -172,7 +174,19 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, switch (op->common.node->type) { /* * For these types, we need the actual node, not the subobject. - * However, the subobject got an extra reference count above. + * However, the subobject did not get an extra reference count above. + * + * TBD: should ex_resolve_node_to_value be changed to fix this? + */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + acpi_ut_add_reference(op->common.node->object); + + /*lint -fallthrough */ + /* + * For these types, we need the actual node, not the subobject. + * The subobject got an extra reference count in ex_resolve_node_to_value. */ case ACPI_TYPE_MUTEX: case ACPI_TYPE_METHOD: @@ -180,25 +194,15 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_EVENT: case ACPI_TYPE_REGION: - case ACPI_TYPE_DEVICE: - case ACPI_TYPE_THERMAL: - obj_desc = - (union acpi_operand_object *)op->common. - node; + /* We will create a reference object for these types below */ break; default: - break; - } - - /* - * If above resolved to an operand object, we are done. Otherwise, - * we have a NS node, we must create the package entry as a named - * reference. - */ - if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != - ACPI_DESC_TYPE_NAMED) { + /* + * All other types - the node was resolved to an actual + * object, we are done. + */ goto exit; } } @@ -223,7 +227,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, exit: *obj_desc_ptr = obj_desc; - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } /******************************************************************************* @@ -369,7 +373,9 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, union acpi_parse_object *parent; union acpi_operand_object *obj_desc = NULL; acpi_status status = AE_OK; - acpi_native_uint i; + unsigned i; + u16 index; + u16 reference_count; ACPI_FUNCTION_TRACE(ds_build_internal_package_obj); @@ -447,13 +453,60 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, package. elements[i]); } + + if (*obj_desc_ptr) { + + /* Existing package, get existing reference count */ + + reference_count = + (*obj_desc_ptr)->common.reference_count; + if (reference_count > 1) { + + /* Make new element ref count match original ref count */ + + for (index = 0; index < (reference_count - 1); + index++) { + acpi_ut_add_reference((obj_desc-> + package. + elements[i])); + } + } + } + arg = arg->common.next; } - if (!arg) { + /* Check for match between num_elements and actual length of package_list */ + + if (arg) { + /* + * num_elements was exhausted, but there are remaining elements in the + * package_list. + * + * Note: technically, this is an error, from ACPI spec: "It is an error + * for NumElements to be less than the number of elements in the + * PackageList". However, for now, we just print an error message and + * no exception is returned. + */ + while (arg) { + + /* Find out how many elements there really are */ + + i++; + arg = arg->common.next; + } + + ACPI_ERROR((AE_INFO, + "Package List length (%X) larger than NumElements count (%X), truncated\n", + i, element_count)); + } else if (i < element_count) { + /* + * Arg list (elements) was exhausted, but we did not reach num_elements count. + * Note: this is not an error, the package is padded out with NULLs. + */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Package List length larger than NumElements count (%X), truncated\n", - element_count)); + "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n", + i, element_count)); } obj_desc->package.flags |= AOPOBJ_DATA_VALID; @@ -721,6 +774,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Node was saved in Op */ obj_desc->reference.node = op->common.node; + obj_desc->reference.object = + op->common.node->object; } obj_desc->reference.opcode = opcode; diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index f501e083aac7..a818e0ddb996 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,7 @@ #include <acpi/acinterp.h> #include <acpi/acnamesp.h> #include <acpi/acevents.h> +#include <acpi/actables.h> #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsopcode") @@ -219,6 +220,50 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) /******************************************************************************* * + * FUNCTION: acpi_ds_get_bank_field_arguments + * + * PARAMETERS: obj_desc - A valid bank_field object + * + * RETURN: Status. + * + * DESCRIPTION: Get bank_field bank_value. This implements the late + * evaluation of these field attributes. + * + ******************************************************************************/ + +acpi_status +acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc) +{ + union acpi_operand_object *extra_desc; + struct acpi_namespace_node *node; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc); + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS(AE_OK); + } + + /* Get the AML pointer (method object) and bank_field node */ + + extra_desc = acpi_ns_get_secondary_object(obj_desc); + node = obj_desc->bank_field.node; + + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname + (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n", + acpi_ut_get_node_name(node))); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node), + extra_desc->extra.aml_length, + extra_desc->extra.aml_start); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * * FUNCTION: acpi_ds_get_buffer_arguments * * PARAMETERS: obj_desc - A valid Buffer object @@ -770,7 +815,109 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, - ACPI_FORMAT_UINT64(obj_desc->region.address), + ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address), + obj_desc->region.length)); + + /* Now the address and length are valid for this opregion */ + + obj_desc->region.flags |= AOPOBJ_DATA_VALID; + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_eval_table_region_operands + * + * PARAMETERS: walk_state - Current walk + * Op - A valid region Op object + * + * RETURN: Status + * + * DESCRIPTION: Get region address and length + * Called from acpi_ds_exec_end_op during data_table_region parse tree walk + * + ******************************************************************************/ + +acpi_status +acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + union acpi_operand_object **operand; + struct acpi_namespace_node *node; + union acpi_parse_object *next_op; + acpi_native_uint table_index; + struct acpi_table_header *table; + + ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op); + + /* + * This is where we evaluate the signature_string and oem_iDString + * and oem_table_iDString of the data_table_region declaration + */ + node = op->common.node; + + /* next_op points to signature_string op */ + + next_op = op->common.value.arg; + + /* + * Evaluate/create the signature_string and oem_iDString + * and oem_table_iDString operands + */ + status = acpi_ds_create_operands(walk_state, next_op); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * Resolve the signature_string and oem_iDString + * and oem_table_iDString operands + */ + status = acpi_ex_resolve_operands(op->common.aml_opcode, + ACPI_WALK_OPERANDS, walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name(op->common.aml_opcode), + 1, "after AcpiExResolveOperands"); + + operand = &walk_state->operands[0]; + + /* Find the ACPI table */ + + status = acpi_tb_find_table(operand[0]->string.pointer, + operand[1]->string.pointer, + operand[2]->string.pointer, &table_index); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + acpi_ut_remove_reference(operand[0]); + acpi_ut_remove_reference(operand[1]); + acpi_ut_remove_reference(operand[2]); + + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + obj_desc = acpi_ns_get_attached_object(node); + if (!obj_desc) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + + obj_desc->region.address = + (acpi_physical_address) ACPI_TO_INTEGER(table); + obj_desc->region.length = table->length; + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", + obj_desc, + ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ @@ -808,6 +955,12 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, /* The first operand (for all of these data objects) is the length */ + /* + * Set proper index into operand stack for acpi_ds_obj_stack_push + * invoked inside acpi_ds_create_operand. + */ + walk_state->operand_index = walk_state->num_operands; + status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -878,6 +1031,106 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, /******************************************************************************* * + * FUNCTION: acpi_ds_eval_bank_field_operands + * + * PARAMETERS: walk_state - Current walk + * Op - A valid bank_field Op object + * + * RETURN: Status + * + * DESCRIPTION: Get bank_field bank_value + * Called from acpi_ds_exec_end_op during bank_field parse tree walk + * + ******************************************************************************/ + +acpi_status +acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + union acpi_operand_object *operand_desc; + struct acpi_namespace_node *node; + union acpi_parse_object *next_op; + union acpi_parse_object *arg; + + ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op); + + /* + * This is where we evaluate the bank_value field of the + * bank_field declaration + */ + + /* next_op points to the op that holds the Region */ + + next_op = op->common.value.arg; + + /* next_op points to the op that holds the Bank Register */ + + next_op = next_op->common.next; + + /* next_op points to the op that holds the Bank Value */ + + next_op = next_op->common.next; + + /* + * Set proper index into operand stack for acpi_ds_obj_stack_push + * invoked inside acpi_ds_create_operand. + * + * We use walk_state->Operands[0] to store the evaluated bank_value + */ + walk_state->operand_index = 0; + + status = acpi_ds_create_operand(walk_state, next_op, 0); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name(op->common.aml_opcode), + 1, "after AcpiExResolveOperands"); + + /* + * Get the bank_value operand and save it + * (at Top of stack) + */ + operand_desc = walk_state->operands[0]; + + /* Arg points to the start Bank Field */ + + arg = acpi_ps_get_arg(op, 4); + while (arg) { + + /* Ignore OFFSET and ACCESSAS terms here */ + + if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { + node = arg->common.node; + + obj_desc = acpi_ns_get_attached_object(node); + if (!obj_desc) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + + obj_desc->bank_field.value = + (u32) operand_desc->integer.value; + } + + /* Move to next field in the list */ + + arg = arg->common.next; + } + + acpi_ut_remove_reference(operand_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * * FUNCTION: acpi_ds_exec_begin_control_op * * PARAMETERS: walk_list - The list that owns the walk stack @@ -1070,8 +1323,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, * is set to anything other than zero! */ walk_state->return_desc = walk_state->operands[0]; - } else if ((walk_state->results) && - (walk_state->results->results.num_results > 0)) { + } else if (walk_state->result_count) { /* Since we have a real Return(), delete any implicit return */ diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 71503c036f7c..b398982f0d8b 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -278,7 +278,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op, AML_VAR_PACKAGE_OP) || (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || (op->common.parent->common.aml_opcode == - AML_INT_EVAL_SUBTREE_OP)) { + AML_INT_EVAL_SUBTREE_OP) + || (op->common.parent->common.aml_opcode == + AML_BANK_FIELD_OP)) { /* * These opcodes allow term_arg(s) as operands and therefore * the operands can be method calls. The result is used. @@ -472,7 +474,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* A valid name must be looked up in the namespace */ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && - (arg->common.value.string)) { + (arg->common.value.string) && + !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", arg)); @@ -595,7 +598,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, } else { /* Check for null name case */ - if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) { + if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && + !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) { /* * If the name is null, this means that this is an * optional result parameter that was not specified @@ -617,7 +621,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NOT_IMPLEMENTED); } - if (op_info->flags & AML_HAS_RETVAL) { + if ((op_info->flags & AML_HAS_RETVAL) + || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Argument previously created, already stacked\n")); @@ -630,9 +635,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, * Use value that was already previously returned * by the evaluation of this argument */ - status = - acpi_ds_result_pop_from_bottom(&obj_desc, - walk_state); + status = acpi_ds_result_pop(&obj_desc, walk_state); if (ACPI_FAILURE(status)) { /* * Only error is underflow, and this indicates @@ -698,27 +701,52 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, { acpi_status status = AE_OK; union acpi_parse_object *arg; + union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS]; u32 arg_count = 0; + u32 index = walk_state->num_operands; + u32 i; ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg); - /* For all arguments in the list... */ + /* Get all arguments in the list */ arg = first_arg; while (arg) { - status = acpi_ds_create_operand(walk_state, arg, arg_count); - if (ACPI_FAILURE(status)) { - goto cleanup; + if (index >= ACPI_OBJ_NUM_OPERANDS) { + return_ACPI_STATUS(AE_BAD_DATA); } - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Arg #%d (%p) done, Arg1=%p\n", arg_count, - arg, first_arg)); + arguments[index] = arg; + walk_state->operands[index] = NULL; /* Move on to next argument, if any */ arg = arg->common.next; arg_count++; + index++; + } + + index--; + + /* It is the appropriate order to get objects from the Result stack */ + + for (i = 0; i < arg_count; i++) { + arg = arguments[index]; + + /* Force the filling of the operand stack in inverse order */ + + walk_state->operand_index = (u8) index; + + status = acpi_ds_create_operand(walk_state, arg, index); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + + index--; + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Arg #%d (%p) done, Arg1=%p\n", index, arg, + first_arg)); } return_ACPI_STATUS(status); @@ -729,9 +757,112 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, * pop everything off of the operand stack and delete those * objects */ - (void)acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state); + acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state); + + ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index)); + return_ACPI_STATUS(status); +} + +/***************************************************************************** + * + * FUNCTION: acpi_ds_evaluate_name_path + * + * PARAMETERS: walk_state - Current state of the parse tree walk, + * the opcode of current operation should be + * AML_INT_NAMEPATH_OP + * + * RETURN: Status + * + * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent + * interpreter object, convert it to value, if needed, duplicate + * it, if needed, and push it onto the current result stack. + * + ****************************************************************************/ + +acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_parse_object *op = walk_state->op; + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *new_obj_desc; + u8 type; + + ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state); + + if (!op->common.parent) { + + /* This happens after certain exception processing */ + + goto exit; + } + + if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) { + + /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */ + + goto exit; + } + + status = acpi_ds_create_operand(walk_state, op, 0); + if (ACPI_FAILURE(status)) { + goto exit; + } + + if (op->common.flags & ACPI_PARSEOP_TARGET) { + new_obj_desc = *operand; + goto push_result; + } + + type = ACPI_GET_OBJECT_TYPE(*operand); + + status = acpi_ex_resolve_to_value(operand, walk_state); + if (ACPI_FAILURE(status)) { + goto exit; + } + + if (type == ACPI_TYPE_INTEGER) { + + /* It was incremented by acpi_ex_resolve_to_value */ + + acpi_ut_remove_reference(*operand); + + status = + acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc, + walk_state); + if (ACPI_FAILURE(status)) { + goto exit; + } + } else { + /* + * The object either was anew created or is + * a Namespace node - don't decrement it. + */ + new_obj_desc = *operand; + } + + /* Cleanup for name-path operand */ + + status = acpi_ds_obj_stack_pop(1, walk_state); + if (ACPI_FAILURE(status)) { + walk_state->result_obj = new_obj_desc; + goto exit; + } + + push_result: + + walk_state->result_obj = new_obj_desc; + + status = acpi_ds_result_push(walk_state->result_obj, walk_state); + if (ACPI_SUCCESS(status)) { + + /* Force to take it from stack */ + + op->common.flags |= ACPI_PARSEOP_IN_STACK; + } + + exit: - ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", - (arg_count + 1))); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 69693fa07224..b246b9657ead 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -285,11 +285,6 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, switch (opcode_class) { case AML_CLASS_CONTROL: - status = acpi_ds_result_stack_push(walk_state); - if (ACPI_FAILURE(status)) { - goto error_exit; - } - status = acpi_ds_exec_begin_control_op(walk_state, op); break; @@ -305,20 +300,11 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, status = acpi_ds_load2_begin_op(walk_state, NULL); } - if (op->common.aml_opcode == AML_REGION_OP) { - status = acpi_ds_result_stack_push(walk_state); - } break; case AML_CLASS_EXECUTE: case AML_CLASS_CREATE: - /* - * Most operators with arguments (except create_xxx_field operators) - * Start a new result/operand state - */ - if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) { - status = acpi_ds_result_stack_push(walk_state); - } + break; default: @@ -374,6 +360,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) /* Init the walk state */ walk_state->num_operands = 0; + walk_state->operand_index = 0; walk_state->return_desc = NULL; walk_state->result_obj = NULL; @@ -388,10 +375,17 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) /* Decode the Opcode Class */ switch (op_class) { - case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */ + case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */ + + if (walk_state->opcode == AML_INT_NAMEPATH_OP) { + status = acpi_ds_evaluate_name_path(walk_state); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + } break; - case AML_CLASS_EXECUTE: /* most operators with arguments */ + case AML_CLASS_EXECUTE: /* Most operators with arguments */ /* Build resolved operand stack */ @@ -400,13 +394,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) goto cleanup; } - /* Done with this result state (Now that operand stack is built) */ - - status = acpi_ds_result_stack_pop(walk_state); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - /* * All opcodes require operand resolution, with the only exceptions * being the object_type and size_of operators. @@ -487,16 +474,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) status = acpi_ds_exec_end_control_op(walk_state, op); - /* Make sure to properly pop the result stack */ - - if (ACPI_SUCCESS(status)) { - status = acpi_ds_result_stack_pop(walk_state); - } else if (status == AE_CTRL_PENDING) { - status = acpi_ds_result_stack_pop(walk_state); - if (ACPI_SUCCESS(status)) { - status = AE_CTRL_PENDING; - } - } break; case AML_TYPE_METHOD_CALL: @@ -516,7 +493,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) op->common.node = (struct acpi_namespace_node *)op->asl.value. - arg->asl.node->object; + arg->asl.node; acpi_ut_add_reference(op->asl.value.arg->asl. node->object); return_ACPI_STATUS(AE_OK); @@ -632,13 +609,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) break; } - /* Done with result state (Now that operand stack is built) */ - - status = acpi_ds_result_stack_pop(walk_state); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - /* * If a result object was returned from above, push it on the * current result stack @@ -671,8 +641,28 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { break; } + } else if (op->common.aml_opcode == AML_DATA_REGION_OP) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Executing DataTableRegion Strings Op=%p\n", + op)); + + status = + acpi_ds_eval_table_region_operands + (walk_state, op); + if (ACPI_FAILURE(status)) { + break; + } + } else if (op->common.aml_opcode == AML_BANK_FIELD_OP) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Executing BankField Op=%p\n", + op)); - status = acpi_ds_result_stack_pop(walk_state); + status = + acpi_ds_eval_bank_field_operands(walk_state, + op); + if (ACPI_FAILURE(status)) { + break; + } } break; diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index 8ab9d1b29a4c..dff7a3e445a8 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -443,6 +443,15 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } + } else if (op->common.aml_opcode == AML_DATA_REGION_OP) { + status = + acpi_ex_create_region(op->named.data, + op->named.length, + REGION_DATA_TABLE, + walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } } } #endif @@ -767,6 +776,12 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, acpi_ns_lookup(walk_state->scope_info, buffer_ptr, object_type, ACPI_IMODE_LOAD_PASS2, flags, walk_state, &node); + + if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "***New Node [%4.4s] %p is temporary\n", + acpi_ut_get_node_name(node), node)); + } break; } @@ -823,6 +838,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) struct acpi_namespace_node *new_node; #ifndef ACPI_NO_METHOD_EXECUTION u32 i; + u8 region_space; #endif ACPI_FUNCTION_TRACE(ds_load2_end_op); @@ -1003,11 +1019,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) status = acpi_ex_create_event(walk_state); break; - case AML_DATA_REGION_OP: - - status = acpi_ex_create_table_region(walk_state); - break; - case AML_ALIAS_OP: status = acpi_ex_create_alias(walk_state); @@ -1035,6 +1046,15 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) switch (op->common.aml_opcode) { #ifndef ACPI_NO_METHOD_EXECUTION case AML_REGION_OP: + case AML_DATA_REGION_OP: + + if (op->common.aml_opcode == AML_REGION_OP) { + region_space = (acpi_adr_space_type) + ((op->common.value.arg)->common.value. + integer); + } else { + region_space = REGION_DATA_TABLE; + } /* * If we are executing a method, initialize the region @@ -1043,10 +1063,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) status = acpi_ex_create_region(op->named.data, op->named.length, - (acpi_adr_space_type) - ((op->common.value. - arg)->common.value. - integer), + region_space, walk_state); if (ACPI_FAILURE(status)) { return (status); diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index 3927c495e4bf..9e6073265873 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 5afcdd9c7449..1386ced332ec 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,85 +49,9 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswstate") -/* Local prototypes */ -#ifdef ACPI_OBSOLETE_FUNCTIONS -acpi_status -acpi_ds_result_insert(void *object, - u32 index, struct acpi_walk_state *walk_state); - -acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state *walk_state); - -acpi_status -acpi_ds_obj_stack_pop_object(union acpi_operand_object **object, - struct acpi_walk_state *walk_state); - -void *acpi_ds_obj_stack_get_value(u32 index, - struct acpi_walk_state *walk_state); -#endif - -#ifdef ACPI_FUTURE_USAGE -/******************************************************************************* - * - * FUNCTION: acpi_ds_result_remove - * - * PARAMETERS: Object - Where to return the popped object - * Index - Where to extract the object - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In - * other words, this is a FIFO. - * - ******************************************************************************/ - -acpi_status -acpi_ds_result_remove(union acpi_operand_object **object, - u32 index, struct acpi_walk_state *walk_state) -{ - union acpi_generic_state *state; - - ACPI_FUNCTION_NAME(ds_result_remove); - - state = walk_state->results; - if (!state) { - ACPI_ERROR((AE_INFO, "No result object pushed! State=%p", - walk_state)); - return (AE_NOT_EXIST); - } - - if (index >= ACPI_OBJ_MAX_OPERAND) { - ACPI_ERROR((AE_INFO, - "Index out of range: %X State=%p Num=%X", - index, walk_state, state->results.num_results)); - } - - /* Check for a valid result object */ - - if (!state->results.obj_desc[index]) { - ACPI_ERROR((AE_INFO, - "Null operand! State=%p #Ops=%X, Index=%X", - walk_state, state->results.num_results, index)); - return (AE_AML_NO_RETURN_VALUE); - } - - /* Remove the object */ - - state->results.num_results--; - - *object = state->results.obj_desc[index]; - state->results.obj_desc[index] = NULL; - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Obj=%p [%s] Index=%X State=%p Num=%X\n", - *object, - (*object) ? acpi_ut_get_object_type_name(*object) : - "NULL", index, walk_state, - state->results.num_results)); - - return (AE_OK); -} -#endif /* ACPI_FUTURE_USAGE */ + /* Local prototypes */ +static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws); +static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws); /******************************************************************************* * @@ -138,122 +62,67 @@ acpi_ds_result_remove(union acpi_operand_object **object, * * RETURN: Status * - * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In - * other words, this is a FIFO. + * DESCRIPTION: Pop an object off the top of this walk's result stack * ******************************************************************************/ acpi_status -acpi_ds_result_pop(union acpi_operand_object ** object, - struct acpi_walk_state * walk_state) +acpi_ds_result_pop(union acpi_operand_object **object, + struct acpi_walk_state *walk_state) { acpi_native_uint index; union acpi_generic_state *state; + acpi_status status; ACPI_FUNCTION_NAME(ds_result_pop); state = walk_state->results; - if (!state) { - return (AE_OK); - } - - if (!state->results.num_results) { - ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p", - walk_state)); - return (AE_AML_NO_RETURN_VALUE); - } - /* Remove top element */ + /* Incorrect state of result stack */ - state->results.num_results--; - - for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) { - - /* Check for a valid result object */ - - if (state->results.obj_desc[index - 1]) { - *object = state->results.obj_desc[index - 1]; - state->results.obj_desc[index - 1] = NULL; - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Obj=%p [%s] Index=%X State=%p Num=%X\n", - *object, - (*object) ? - acpi_ut_get_object_type_name(*object) - : "NULL", (u32) index - 1, walk_state, - state->results.num_results)); - - return (AE_OK); - } + if (state && !walk_state->result_count) { + ACPI_ERROR((AE_INFO, "No results on result stack")); + return (AE_AML_INTERNAL); } - ACPI_ERROR((AE_INFO, "No result objects! State=%p", walk_state)); - return (AE_AML_NO_RETURN_VALUE); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_result_pop_from_bottom - * - * PARAMETERS: Object - Where to return the popped object - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In - * other words, this is a FIFO. - * - ******************************************************************************/ - -acpi_status -acpi_ds_result_pop_from_bottom(union acpi_operand_object ** object, - struct acpi_walk_state * walk_state) -{ - acpi_native_uint index; - union acpi_generic_state *state; + if (!state && walk_state->result_count) { + ACPI_ERROR((AE_INFO, "No result state for result stack")); + return (AE_AML_INTERNAL); + } - ACPI_FUNCTION_NAME(ds_result_pop_from_bottom); + /* Empty result stack */ - state = walk_state->results; if (!state) { - ACPI_ERROR((AE_INFO, - "No result object pushed! State=%p", walk_state)); - return (AE_NOT_EXIST); - } - - if (!state->results.num_results) { - ACPI_ERROR((AE_INFO, "No result objects! State=%p", + ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p", walk_state)); return (AE_AML_NO_RETURN_VALUE); } - /* Remove Bottom element */ - - *object = state->results.obj_desc[0]; - - /* Push entire stack down one element */ - - for (index = 0; index < state->results.num_results; index++) { - state->results.obj_desc[index] = - state->results.obj_desc[index + 1]; - } + /* Return object of the top element and clean that top element result stack */ - state->results.num_results--; - - /* Check for a valid result object */ + walk_state->result_count--; + index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + *object = state->results.obj_desc[index]; if (!*object) { ACPI_ERROR((AE_INFO, - "Null operand! State=%p #Ops=%X Index=%X", - walk_state, state->results.num_results, - (u32) index)); + "No result objects on result stack, State=%p", + walk_state)); return (AE_AML_NO_RETURN_VALUE); } - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] Results=%p State=%p\n", - *object, - (*object) ? acpi_ut_get_object_type_name(*object) : - "NULL", state, walk_state)); + state->results.obj_desc[index] = NULL; + if (index == 0) { + status = acpi_ds_result_stack_pop(walk_state); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object, + acpi_ut_get_object_type_name(*object), + (u32) index, walk_state, walk_state->result_count)); return (AE_OK); } @@ -276,39 +145,56 @@ acpi_ds_result_push(union acpi_operand_object * object, struct acpi_walk_state * walk_state) { union acpi_generic_state *state; + acpi_status status; + acpi_native_uint index; ACPI_FUNCTION_NAME(ds_result_push); + if (walk_state->result_count > walk_state->result_size) { + ACPI_ERROR((AE_INFO, "Result stack is full")); + return (AE_AML_INTERNAL); + } else if (walk_state->result_count == walk_state->result_size) { + + /* Extend the result stack */ + + status = acpi_ds_result_stack_push(walk_state); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, + "Failed to extend the result stack")); + return (status); + } + } + + if (!(walk_state->result_count < walk_state->result_size)) { + ACPI_ERROR((AE_INFO, "No free elements in result stack")); + return (AE_AML_INTERNAL); + } + state = walk_state->results; if (!state) { ACPI_ERROR((AE_INFO, "No result stack frame during push")); return (AE_AML_INTERNAL); } - if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) { - ACPI_ERROR((AE_INFO, - "Result stack overflow: Obj=%p State=%p Num=%X", - object, walk_state, state->results.num_results)); - return (AE_STACK_OVERFLOW); - } - if (!object) { ACPI_ERROR((AE_INFO, "Null Object! Obj=%p State=%p Num=%X", - object, walk_state, state->results.num_results)); + object, walk_state, walk_state->result_count)); return (AE_BAD_PARAMETER); } - state->results.obj_desc[state->results.num_results] = object; - state->results.num_results++; + /* Assign the address of object to the top free element of result stack */ + + index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + state->results.obj_desc[index] = object; + walk_state->result_count++; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n", object, - object ? acpi_ut_get_object_type_name((union acpi_operand_object *) - object) : "NULL", - walk_state, state->results.num_results, + object), walk_state, + walk_state->result_count, walk_state->current_result)); return (AE_OK); @@ -322,16 +208,25 @@ acpi_ds_result_push(union acpi_operand_object * object, * * RETURN: Status * - * DESCRIPTION: Push an object onto the walk_state result stack. + * DESCRIPTION: Push an object onto the walk_state result stack * ******************************************************************************/ -acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state) +static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state) { union acpi_generic_state *state; ACPI_FUNCTION_NAME(ds_result_stack_push); + /* Check for stack overflow */ + + if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) > + ACPI_RESULTS_OBJ_NUM_MAX) { + ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%X", + walk_state, walk_state->result_size)); + return (AE_STACK_OVERFLOW); + } + state = acpi_ut_create_generic_state(); if (!state) { return (AE_NO_MEMORY); @@ -340,6 +235,10 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state) state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT; acpi_ut_push_generic_state(&walk_state->results, state); + /* Increase the length of the result stack by the length of frame */ + + walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM; + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n", state, walk_state)); @@ -354,11 +253,11 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state) * * RETURN: Status * - * DESCRIPTION: Pop an object off of the walk_state result stack. + * DESCRIPTION: Pop an object off of the walk_state result stack * ******************************************************************************/ -acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state) +static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state) { union acpi_generic_state *state; @@ -367,18 +266,27 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state) /* Check for stack underflow */ if (walk_state->results == NULL) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Underflow - State=%p\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Result stack underflow - State=%p\n", walk_state)); return (AE_AML_NO_OPERAND); } + if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) { + ACPI_ERROR((AE_INFO, "Insufficient result stack size")); + return (AE_AML_INTERNAL); + } + state = acpi_ut_pop_generic_state(&walk_state->results); + acpi_ut_delete_generic_state(state); + + /* Decrease the length of result stack by the length of frame */ + + walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Result=%p RemainingResults=%X State=%p\n", - state, state->results.num_results, walk_state)); - - acpi_ut_delete_generic_state(state); + state, walk_state->result_count, walk_state)); return (AE_OK); } @@ -412,9 +320,13 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state) /* Put the object onto the stack */ - walk_state->operands[walk_state->num_operands] = object; + walk_state->operands[walk_state->operand_index] = object; walk_state->num_operands++; + /* For the usual order of filling the operand stack */ + + walk_state->operand_index++; + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", object, acpi_ut_get_object_type_name((union @@ -484,43 +396,36 @@ acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state) * ******************************************************************************/ -acpi_status +void acpi_ds_obj_stack_pop_and_delete(u32 pop_count, - struct acpi_walk_state * walk_state) + struct acpi_walk_state *walk_state) { - u32 i; + acpi_native_int i; union acpi_operand_object *obj_desc; ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete); - for (i = 0; i < pop_count; i++) { - - /* Check for stack underflow */ + if (pop_count == 0) { + return; + } + for (i = (acpi_native_int) (pop_count - 1); i >= 0; i--) { if (walk_state->num_operands == 0) { - ACPI_ERROR((AE_INFO, - "Object stack underflow! Count=%X State=%p #Ops=%X", - pop_count, walk_state, - walk_state->num_operands)); - return (AE_STACK_UNDERFLOW); + return; } /* Pop the stack and delete an object if present in this stack entry */ walk_state->num_operands--; - obj_desc = walk_state->operands[walk_state->num_operands]; + obj_desc = walk_state->operands[i]; if (obj_desc) { - acpi_ut_remove_reference(walk_state-> - operands[walk_state-> - num_operands]); - walk_state->operands[walk_state->num_operands] = NULL; + acpi_ut_remove_reference(walk_state->operands[i]); + walk_state->operands[i] = NULL; } } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", pop_count, walk_state, walk_state->num_operands)); - - return (AE_OK); } /******************************************************************************* @@ -560,7 +465,7 @@ struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state * * RETURN: None * - * DESCRIPTION: Place the Thread state at the head of the state list. + * DESCRIPTION: Place the Thread state at the head of the state list * ******************************************************************************/ @@ -636,7 +541,6 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union *thread) { struct acpi_walk_state *walk_state; - acpi_status status; ACPI_FUNCTION_TRACE(ds_create_walk_state); @@ -659,14 +563,6 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_ds_method_data_init(walk_state); #endif - /* Create an initial result stack entry */ - - status = acpi_ds_result_stack_push(walk_state); - if (ACPI_FAILURE(status)) { - ACPI_FREE(walk_state); - return_PTR(NULL); - } - /* Put the new state at the head of the walk list */ if (thread) { @@ -860,190 +756,3 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) ACPI_FREE(walk_state); return_VOID; } - -#ifdef ACPI_OBSOLETE_FUNCTIONS -/******************************************************************************* - * - * FUNCTION: acpi_ds_result_insert - * - * PARAMETERS: Object - Object to push - * Index - Where to insert the object - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Insert an object onto this walk's result stack - * - ******************************************************************************/ - -acpi_status -acpi_ds_result_insert(void *object, - u32 index, struct acpi_walk_state *walk_state) -{ - union acpi_generic_state *state; - - ACPI_FUNCTION_NAME(ds_result_insert); - - state = walk_state->results; - if (!state) { - ACPI_ERROR((AE_INFO, "No result object pushed! State=%p", - walk_state)); - return (AE_NOT_EXIST); - } - - if (index >= ACPI_OBJ_NUM_OPERANDS) { - ACPI_ERROR((AE_INFO, - "Index out of range: %X Obj=%p State=%p Num=%X", - index, object, walk_state, - state->results.num_results)); - return (AE_BAD_PARAMETER); - } - - if (!object) { - ACPI_ERROR((AE_INFO, - "Null Object! Index=%X Obj=%p State=%p Num=%X", - index, object, walk_state, - state->results.num_results)); - return (AE_BAD_PARAMETER); - } - - state->results.obj_desc[index] = object; - state->results.num_results++; - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Obj=%p [%s] State=%p Num=%X Cur=%X\n", - object, - object ? - acpi_ut_get_object_type_name((union - acpi_operand_object *) - object) : "NULL", - walk_state, state->results.num_results, - walk_state->current_result)); - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_delete_all - * - * PARAMETERS: walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Clear the object stack by deleting all objects that are on it. - * Should be used with great care, if at all! - * - ******************************************************************************/ - -acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state * walk_state) -{ - u32 i; - - ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_delete_all, walk_state); - - /* The stack size is configurable, but fixed */ - - for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { - if (walk_state->operands[i]) { - acpi_ut_remove_reference(walk_state->operands[i]); - walk_state->operands[i] = NULL; - } - } - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_pop_object - * - * PARAMETERS: Object - Where to return the popped object - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT - * deleted by this routine. - * - ******************************************************************************/ - -acpi_status -acpi_ds_obj_stack_pop_object(union acpi_operand_object **object, - struct acpi_walk_state *walk_state) -{ - ACPI_FUNCTION_NAME(ds_obj_stack_pop_object); - - /* Check for stack underflow */ - - if (walk_state->num_operands == 0) { - ACPI_ERROR((AE_INFO, - "Missing operand/stack empty! State=%p #Ops=%X", - walk_state, walk_state->num_operands)); - *object = NULL; - return (AE_AML_NO_OPERAND); - } - - /* Pop the stack */ - - walk_state->num_operands--; - - /* Check for a valid operand */ - - if (!walk_state->operands[walk_state->num_operands]) { - ACPI_ERROR((AE_INFO, - "Null operand! State=%p #Ops=%X", - walk_state, walk_state->num_operands)); - *object = NULL; - return (AE_AML_NO_OPERAND); - } - - /* Get operand and set stack entry to null */ - - *object = walk_state->operands[walk_state->num_operands]; - walk_state->operands[walk_state->num_operands] = NULL; - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", - *object, acpi_ut_get_object_type_name(*object), - walk_state, walk_state->num_operands)); - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_get_value - * - * PARAMETERS: Index - Stack index whose value is desired. Based - * on the top of the stack (index=0 == top) - * walk_state - Current Walk state - * - * RETURN: Pointer to the requested operand - * - * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must - * be within the range of the current stack pointer. - * - ******************************************************************************/ - -void *acpi_ds_obj_stack_get_value(u32 index, struct acpi_walk_state *walk_state) -{ - - ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_get_value, walk_state); - - /* Can't do it if the stack is empty */ - - if (walk_state->num_operands == 0) { - return_PTR(NULL); - } - - /* or if the index is past the top of the stack */ - - if (index > (walk_state->num_operands - (u32) 1)) { - return_PTR(NULL); - } - - return_PTR(walk_state-> - operands[(acpi_native_uint) (walk_state->num_operands - 1) - - index]); -} -#endif diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7222a18a0319..0924992187e8 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -73,38 +73,14 @@ enum ec_event { #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ +#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ enum { EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ - EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */ - EC_FLAGS_ADDRESS, /* Address is being written */ - EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ - EC_FLAGS_WDATA, /* Data is being written */ - EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */ -}; - -static int acpi_ec_remove(struct acpi_device *device, int type); -static int acpi_ec_start(struct acpi_device *device); -static int acpi_ec_stop(struct acpi_device *device, int type); -static int acpi_ec_add(struct acpi_device *device); - -static const struct acpi_device_id ec_device_ids[] = { - {"PNP0C09", 0}, - {"", 0}, -}; - -static struct acpi_driver acpi_ec_driver = { - .name = "ec", - .class = ACPI_EC_CLASS, - .ids = ec_device_ids, - .ops = { - .add = acpi_ec_add, - .remove = acpi_ec_remove, - .start = acpi_ec_start, - .stop = acpi_ec_stop, - }, + EC_FLAGS_NO_GPE, /* Don't use GPE mode */ + EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -129,6 +105,8 @@ static struct acpi_ec { struct mutex lock; wait_queue_head_t wait; struct list_head list; + struct delayed_work work; + atomic_t irq_count; u8 handlers_installed; } *boot_ec, *first_ec; @@ -177,65 +155,52 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) return 0; } -static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) +static void ec_schedule_ec_poll(struct acpi_ec *ec) { - int ret = 0; + if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) + schedule_delayed_work(&ec->work, + msecs_to_jiffies(ACPI_EC_DELAY)); +} + +static void ec_switch_to_poll_mode(struct acpi_ec *ec) +{ + set_bit(EC_FLAGS_NO_GPE, &ec->flags); + clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); + acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); +} - if (unlikely(event == ACPI_EC_EVENT_OBF_1 && - test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags))) - force_poll = 1; - if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && - test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) - force_poll = 1; - if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) && - test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags))) - force_poll = 1; +static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) +{ + atomic_set(&ec->irq_count, 0); if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && likely(!force_poll)) { if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), msecs_to_jiffies(ACPI_EC_DELAY))) - goto end; + return 0; clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); if (acpi_ec_check_status(ec, event)) { - if (event == ACPI_EC_EVENT_OBF_1) { - /* miss OBF_1 GPE, don't expect it */ - pr_info(PREFIX "missing OBF confirmation, " - "don't expect it any longer.\n"); - set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags); - } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { - /* miss address GPE, don't expect it anymore */ - pr_info(PREFIX "missing address confirmation, " - "don't expect it any longer.\n"); - set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags); - } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) { - /* miss write data GPE, don't expect it */ - pr_info(PREFIX "missing write data confirmation, " - "don't expect it any longer.\n"); - set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags); - } else { - /* missing GPEs, switch back to poll mode */ - if (printk_ratelimit()) - pr_info(PREFIX "missing confirmations, " + /* missing GPEs, switch back to poll mode */ + if (printk_ratelimit()) + pr_info(PREFIX "missing confirmations, " "switch off interrupt mode.\n"); - clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); - } - goto end; + ec_switch_to_poll_mode(ec); + ec_schedule_ec_poll(ec); + return 0; } } else { unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); while (time_before(jiffies, delay)) { if (acpi_ec_check_status(ec, event)) - goto end; + return 0; + udelay(ACPI_EC_UDELAY); } } - pr_err(PREFIX "acpi_ec_wait timeout," - " status = %d, expect_event = %d\n", - acpi_ec_read_status(ec), event); - ret = -ETIME; - end: - clear_bit(EC_FLAGS_ADDRESS, &ec->flags); - return ret; + pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", + acpi_ec_read_status(ec), + (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\""); + return -ETIME; } static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, @@ -245,8 +210,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, { int result = 0; set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - acpi_ec_write_cmd(ec, command); pr_debug(PREFIX "transaction start\n"); + acpi_ec_write_cmd(ec, command); for (; wdata_len > 0; --wdata_len) { result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); if (result) { @@ -254,15 +219,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, "write_cmd timeout, command = %d\n", command); goto end; } - /* mark the address byte written to EC */ - if (rdata_len + wdata_len > 1) - set_bit(EC_FLAGS_ADDRESS, &ec->flags); set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); acpi_ec_write_data(ec, *(wdata++)); } if (!rdata_len) { - set_bit(EC_FLAGS_WDATA, &ec->flags); result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); if (result) { pr_err(PREFIX @@ -527,47 +488,51 @@ static u32 acpi_ec_gpe_handler(void *data) { acpi_status status = AE_OK; struct acpi_ec *ec = data; + u8 state = acpi_ec_read_status(ec); pr_debug(PREFIX "~~~> interrupt\n"); + atomic_inc(&ec->irq_count); + if (atomic_read(&ec->irq_count) > 5) { + pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); + ec_switch_to_poll_mode(ec); + goto end; + } clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) wake_up(&ec->wait); - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { + if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); - } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) { + } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && + !test_bit(EC_FLAGS_NO_GPE, &ec->flags) && + in_interrupt()) { /* this is non-query, must be confirmation */ if (printk_ratelimit()) pr_info(PREFIX "non-query interrupt received," " switching to interrupt mode\n"); set_bit(EC_FLAGS_GPE_MODE, &ec->flags); + clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); } - +end: + ec_schedule_ec_poll(ec); return ACPI_SUCCESS(status) ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } +static void do_ec_poll(struct work_struct *work) +{ + struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); + atomic_set(&ec->irq_count, 0); + (void)acpi_ec_gpe_handler(ec); +} + /* -------------------------------------------------------------------------- Address Space Management -------------------------------------------------------------------------- */ static acpi_status -acpi_ec_space_setup(acpi_handle region_handle, - u32 function, void *handler_context, void **return_context) -{ - /* - * The EC object is in the handler context and is needed - * when calling the acpi_ec_space_handler. - */ - *return_context = (function != ACPI_REGION_DEACTIVATE) ? - handler_context : NULL; - - return AE_OK; -} - -static acpi_status acpi_ec_space_handler(u32 function, acpi_physical_address address, u32 bits, acpi_integer *value, void *handler_context, void *region_context) @@ -669,16 +634,11 @@ static int acpi_ec_add_fs(struct acpi_device *device) return -ENODEV; } - entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO, + acpi_device_dir(device), + &acpi_ec_info_ops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_ec_info_ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -709,6 +669,8 @@ static struct acpi_ec *make_acpi_ec(void) mutex_init(&ec->lock); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); + INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); + atomic_set(&ec->irq_count, 0); return ec; } @@ -741,17 +703,21 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); if (ACPI_FAILURE(status)) return status; - /* Find and register all query methods */ - acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, - acpi_ec_register_query_methods, ec, NULL); /* Use the global lock for all EC transactions? */ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); ec->handle = handle; return AE_CTRL_TERMINATE; } +static void ec_poll_stop(struct acpi_ec *ec) +{ + clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); + cancel_delayed_work(&ec->work); +} + static void ec_remove_handlers(struct acpi_ec *ec) { + ec_poll_stop(ec); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err(PREFIX "failed to remove space handler\n"); @@ -771,31 +737,28 @@ static int acpi_ec_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_EC_CLASS); /* Check for boot EC */ - if (boot_ec) { - if (boot_ec->handle == device->handle) { - /* Pre-loaded EC from DSDT, just move pointer */ - ec = boot_ec; - boot_ec = NULL; - goto end; - } else if (boot_ec->handle == ACPI_ROOT_OBJECT) { - /* ECDT-based EC, time to shut it down */ - ec_remove_handlers(boot_ec); - kfree(boot_ec); - first_ec = boot_ec = NULL; + if (boot_ec && + (boot_ec->handle == device->handle || + boot_ec->handle == ACPI_ROOT_OBJECT)) { + ec = boot_ec; + boot_ec = NULL; + } else { + ec = make_acpi_ec(); + if (!ec) + return -ENOMEM; + if (ec_parse_device(device->handle, 0, ec, NULL) != + AE_CTRL_TERMINATE) { + kfree(ec); + return -EINVAL; } } - ec = make_acpi_ec(); - if (!ec) - return -ENOMEM; - - if (ec_parse_device(device->handle, 0, ec, NULL) != - AE_CTRL_TERMINATE) { - kfree(ec); - return -EINVAL; - } ec->handle = device->handle; - end: + + /* Find and register all query methods */ + acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, + acpi_ec_register_query_methods, ec, NULL); + if (!first_ec) first_ec = ec; acpi_driver_data(device) = ec; @@ -870,7 +833,7 @@ static int ec_install_handlers(struct acpi_ec *ec) status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, - &acpi_ec_space_setup, ec); + NULL, ec); if (ACPI_FAILURE(status)) { acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); return -ENODEV; @@ -897,6 +860,7 @@ static int acpi_ec_start(struct acpi_device *device) /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + ec_schedule_ec_poll(ec); return ret; } @@ -924,6 +888,11 @@ int __init acpi_boot_ec_enable(void) return -EFAULT; } +static const struct acpi_device_id ec_device_ids[] = { + {"PNP0C09", 0}, + {"", 0}, +}; + int __init acpi_ec_ecdt_probe(void) { int ret; @@ -944,6 +913,7 @@ int __init acpi_ec_ecdt_probe(void) boot_ec->data_addr = ecdt_ptr->data.address; boot_ec->gpe = ecdt_ptr->gpe; boot_ec->handle = ACPI_ROOT_OBJECT; + acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); } else { /* This workaround is needed only on some broken machines, * which require early EC, but fail to provide ECDT */ @@ -973,6 +943,39 @@ int __init acpi_ec_ecdt_probe(void) return -ENODEV; } +static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state) +{ + struct acpi_ec *ec = acpi_driver_data(device); + /* Stop using GPE */ + set_bit(EC_FLAGS_NO_GPE, &ec->flags); + clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); + acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + return 0; +} + +static int acpi_ec_resume(struct acpi_device *device) +{ + struct acpi_ec *ec = acpi_driver_data(device); + /* Enable use of GPE back */ + clear_bit(EC_FLAGS_NO_GPE, &ec->flags); + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + return 0; +} + +static struct acpi_driver acpi_ec_driver = { + .name = "ec", + .class = ACPI_EC_CLASS, + .ids = ec_device_ids, + .ops = { + .add = acpi_ec_add, + .remove = acpi_ec_remove, + .start = acpi_ec_start, + .stop = acpi_ec_stop, + .suspend = acpi_ec_suspend, + .resume = acpi_ec_resume, + }, +}; + static int __init acpi_ec_init(void) { int result = 0; diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index abec1ca94cf4..0c24bd4d6562 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -102,6 +102,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) } static const struct file_operations acpi_system_event_ops = { + .owner = THIS_MODULE, .open = acpi_system_open_event, .read = acpi_system_read_event, .release = acpi_system_close_event, @@ -294,10 +295,9 @@ static int __init acpi_event_init(void) #ifdef CONFIG_ACPI_PROC_EVENT /* 'event' [R] */ - entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_event_ops; - else + entry = proc_create("event", S_IRUSR, acpi_root_dir, + &acpi_system_event_ops); + if (!entry) return -ENODEV; #endif diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index 3048801a37b5..5d30e5be1b1c 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 0dadd2adc800..5354be44f876 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -248,10 +248,6 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) ACPI_FUNCTION_TRACE(ev_disable_gpe); - if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { - return_ACPI_STATUS(AE_OK); - } - /* Make sure HW enable masks are updated */ status = diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 361ebe6c4a6f..e6c4d4c49e79 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 21cb749d0c75..2113e58e2221 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,22 +49,7 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evmisc") -/* Names for Notify() values, used for debug output */ -#ifdef ACPI_DEBUG_OUTPUT -static const char *acpi_notify_value_names[] = { - "Bus Check", - "Device Check", - "Device Wake", - "Eject Request", - "Device Check Light", - "Frequency Mismatch", - "Bus Mode Mismatch", - "Power Fault" -}; -#endif - /* Pointer to FACS needed for the Global Lock */ - static struct acpi_table_facs *facs = NULL; /* Local prototypes */ @@ -94,7 +79,6 @@ u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node) switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_POWER: case ACPI_TYPE_THERMAL: /* * These are the ONLY objects that can receive ACPI notifications @@ -139,17 +123,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, * initiate soft-off or sleep operation? */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Dispatching Notify(%X) on node %p\n", notify_value, - node)); - - if (notify_value <= 7) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n", - acpi_notify_value_names[notify_value])); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Notify value: 0x%2.2X **Device Specific**\n", - notify_value)); - } + "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n", + acpi_ut_get_node_name(node), node, notify_value, + acpi_ut_get_notify_name(notify_value))); /* Get the notify object attached to the NS Node */ @@ -159,10 +135,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, /* We have the notify object, Get the right handler */ switch (node->type) { + + /* Notify allowed only on these types */ + case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_POWER: if (notify_value <= ACPI_MAX_SYS_NOTIFY) { handler_obj = @@ -179,8 +157,13 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, } } - /* If there is any handler to run, schedule the dispatcher */ - + /* + * If there is any handler to run, schedule the dispatcher. + * Check for: + * 1) Global system notify handler + * 2) Global device notify handler + * 3) Per-device notify handler + */ if ((acpi_gbl_system_notify.handler && (notify_value <= ACPI_MAX_SYS_NOTIFY)) || (acpi_gbl_device_notify.handler @@ -190,6 +173,13 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, return (AE_NO_MEMORY); } + if (!handler_obj) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Executing system notify handler for Notify (%4.4s, %X) node %p\n", + acpi_ut_get_node_name(node), + notify_value, node)); + } + notify_info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY; notify_info->notify.node = node; @@ -202,15 +192,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, if (ACPI_FAILURE(status)) { acpi_ut_delete_generic_state(notify_info); } - } - - if (!handler_obj) { + } else { /* - * There is no per-device notify handler for this device. - * This may or may not be a problem. + * There is no notify handler (per-device or system) for this device. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "No notify handler for Notify(%4.4s, %X) node %p\n", + "No notify handler for Notify (%4.4s, %X) node %p\n", acpi_ut_get_node_name(node), notify_value, node)); } @@ -349,9 +336,10 @@ acpi_status acpi_ev_init_global_lock_handler(void) ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); - status = - acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - (struct acpi_table_header **)&facs); + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -439,7 +427,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) * Only one thread can acquire the GL at a time, the global_lock_mutex * enforces this. This interface releases the interpreter if we must wait. */ - status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, 0); + status = acpi_ex_system_wait_mutex( + acpi_gbl_global_lock_mutex->mutex.os_mutex, 0); if (status == AE_TIME) { if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) { acpi_ev_global_lock_acquired++; @@ -448,9 +437,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) } if (ACPI_FAILURE(status)) { - status = - acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, - timeout); + status = acpi_ex_system_wait_mutex( + acpi_gbl_global_lock_mutex->mutex.os_mutex, + timeout); } if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -460,6 +449,19 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) acpi_ev_global_lock_acquired++; /* + * Update the global lock handle and check for wraparound. The handle is + * only used for the external global lock interfaces, but it is updated + * here to properly handle the case where a single thread may acquire the + * lock via both the AML and the acpi_acquire_global_lock interfaces. The + * handle is therefore updated on the first acquire from a given thread + * regardless of where the acquisition request originated. + */ + acpi_gbl_global_lock_handle++; + if (acpi_gbl_global_lock_handle == 0) { + acpi_gbl_global_lock_handle = 1; + } + + /* * Make sure that a global lock actually exists. If not, just treat * the lock as a standard mutex. */ @@ -555,7 +557,7 @@ acpi_status acpi_ev_release_global_lock(void) /* Release the local GL mutex */ acpi_ev_global_lock_thread_id = NULL; acpi_ev_global_lock_acquired = 0; - acpi_os_release_mutex(acpi_gbl_global_lock_mutex); + acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 58ad09725dd2..1628f5934752 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -394,7 +394,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", ®ion_obj->region.handler->address_space, handler, - ACPI_FORMAT_UINT64(address), + ACPI_FORMAT_NATIVE_UINT(address), acpi_ut_get_region_name(region_obj->region. space_id))); diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index b1aaa0e84588..2e3d2c5e4f4d 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 7e5d15ce2395..2a8b77877610 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 6d866a01f5f4..94a6efe020be 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -758,6 +758,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler) * * DESCRIPTION: Acquire the ACPI Global Lock * + * Note: Allows callers with the same thread ID to acquire the global lock + * multiple times. In other words, externally, the behavior of the global lock + * is identical to an AML mutex. On the first acquire, a new handle is + * returned. On any subsequent calls to acquire by the same thread, the same + * handle is returned. + * ******************************************************************************/ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) { @@ -770,14 +776,19 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) /* Must lock interpreter to prevent race conditions */ acpi_ex_enter_interpreter(); - status = acpi_ev_acquire_global_lock(timeout); - acpi_ex_exit_interpreter(); + + status = acpi_ex_acquire_mutex_object(timeout, + acpi_gbl_global_lock_mutex, + acpi_os_get_thread_id()); if (ACPI_SUCCESS(status)) { - acpi_gbl_global_lock_handle++; + + /* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */ + *handle = acpi_gbl_global_lock_handle; } + acpi_ex_exit_interpreter(); return (status); } @@ -798,11 +809,11 @@ acpi_status acpi_release_global_lock(u32 handle) { acpi_status status; - if (handle != acpi_gbl_global_lock_handle) { + if (!handle || (handle != acpi_gbl_global_lock_handle)) { return (AE_NOT_ACQUIRED); } - status = acpi_ev_release_global_lock(); + status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex); return (status); } diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 9cbd3414a574..99a7502e6a87 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 7bf09c5fb242..e8750807e57d 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 25802f302ffe..24da921d13e3 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,7 +45,6 @@ #include <acpi/acinterp.h> #include <acpi/amlcode.h> #include <acpi/acnamesp.h> -#include <acpi/acevents.h> #include <acpi/actables.h> #include <acpi/acdispat.h> @@ -138,6 +137,14 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ex_load_table_op); + /* Validate lengths for the signature_string, OEMIDString, OEMtable_iD */ + + if ((operand[0]->string.length > ACPI_NAME_SIZE) || + (operand[1]->string.length > ACPI_OEM_ID_SIZE) || + (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + /* Find the ACPI table in the RSDT/XSDT */ status = acpi_tb_find_table(operand[0]->string.pointer, @@ -229,11 +236,18 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, status = acpi_get_table_by_index(table_index, &table); if (ACPI_SUCCESS(status)) { ACPI_INFO((AE_INFO, - "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]", + "Dynamic OEM Table Load - [%.4s] OemId [%.6s] OemTableId [%.8s]", table->signature, table->oem_id, table->oem_table_id)); } + /* Invoke table handler if present */ + + if (acpi_gbl_table_handler) { + (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, + acpi_gbl_table_handler_context); + } + *return_desc = ddb_handle; return_ACPI_STATUS(status); } @@ -268,6 +282,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, struct acpi_table_desc table_desc; acpi_native_uint table_index; acpi_status status; + u32 length; ACPI_FUNCTION_TRACE(ex_load_op); @@ -278,16 +293,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_REGION: + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", + obj_desc, + acpi_ut_get_object_type_name(obj_desc))); + /* Region must be system_memory (from ACPI spec) */ if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", - obj_desc, - acpi_ut_get_object_type_name(obj_desc))); - /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. @@ -299,6 +314,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } } + /* + * We will simply map the memory region for the table. However, the + * memory region is technically not guaranteed to remain stable and + * we may eventually have to copy the table to a local buffer. + */ table_desc.address = obj_desc->region.address; table_desc.length = obj_desc->region.length; table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; @@ -306,18 +326,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ - /* Simply extract the buffer from the buffer object */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Buffer or Field %p %s\n", obj_desc, acpi_ut_get_object_type_name(obj_desc))); - table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header, - obj_desc->buffer.pointer); - table_desc.length = table_desc.pointer->length; - table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; + length = obj_desc->buffer.length; + + /* Must have at least an ACPI table header */ + + if (length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } + + /* Validate checksum here. It won't get validated in tb_add_table */ - obj_desc->buffer.pointer = NULL; + status = + acpi_tb_verify_checksum(ACPI_CAST_PTR + (struct acpi_table_header, + obj_desc->buffer.pointer), length); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * We need to copy the buffer since the original buffer could be + * changed or deleted in the future + */ + table_desc.pointer = ACPI_ALLOCATE(length); + if (!table_desc.pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer, + length); + table_desc.length = length; + table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; break; default: @@ -333,7 +376,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } status = - acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle); + acpi_ex_add_table(table_index, walk_state->scope_info->scope.node, + &ddb_handle); if (ACPI_FAILURE(status)) { /* On error, table_ptr was deallocated above */ @@ -349,11 +393,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* table_ptr was deallocated above */ + acpi_ut_remove_reference(ddb_handle); return_ACPI_STATUS(status); } + /* Invoke table handler if present */ + + if (acpi_gbl_table_handler) { + (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, + table_desc.pointer, + acpi_gbl_table_handler_context); + } + cleanup: if (ACPI_FAILURE(status)) { + + /* Delete allocated buffer or mapping */ + acpi_tb_delete_table(&table_desc); } return_ACPI_STATUS(status); @@ -376,6 +432,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) acpi_status status = AE_OK; union acpi_operand_object *table_desc = ddb_handle; acpi_native_uint table_index; + struct acpi_table_header *table; ACPI_FUNCTION_TRACE(ex_unload_table); @@ -395,17 +452,25 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) table_index = (acpi_native_uint) table_desc->reference.object; + /* Invoke table handler if present */ + + if (acpi_gbl_table_handler) { + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_SUCCESS(status)) { + (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD, + table, + acpi_gbl_table_handler_context); + } + } + /* * Delete the entire namespace under this table Node * (Offset contains the table_id) */ acpi_tb_delete_namespace_by_owner(table_index); - acpi_tb_release_owner_id(table_index); + (void)acpi_tb_release_owner_id(table_index); acpi_tb_set_table_loaded_flag(table_index, FALSE); - /* Delete the table descriptor (ddb_handle) */ - - acpi_ut_remove_reference(table_desc); - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index 79f2c0d42c06..fd954b4ed83d 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index 6e9a23e47fef..60e62c4f0577 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -96,6 +96,9 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) * to the original Node. */ switch (target_node->type) { + + /* For these types, the sub-object can change dynamically via a Store */ + case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: @@ -103,9 +106,18 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) case ACPI_TYPE_BUFFER_FIELD: /* + * These types open a new scope, so we need the NS node in order to access + * any children. + */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + case ACPI_TYPE_LOCAL_SCOPE: + + /* * The new alias has the type ALIAS and points to the original - * NS node, not the object itself. This is because for these - * types, the object can change dynamically via a Store. + * NS node, not the object itself. */ alias_node->type = ACPI_TYPE_LOCAL_ALIAS; alias_node->object = @@ -115,9 +127,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) case ACPI_TYPE_METHOD: /* - * The new alias has the type ALIAS and points to the original - * NS node, not the object itself. This is because for these - * types, the object can change dynamically via a Store. + * Control method aliases need to be differentiated */ alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; alias_node->object = @@ -342,101 +352,6 @@ acpi_ex_create_region(u8 * aml_start, /******************************************************************************* * - * FUNCTION: acpi_ex_create_table_region - * - * PARAMETERS: walk_state - Current state - * - * RETURN: Status - * - * DESCRIPTION: Create a new data_table_region object - * - ******************************************************************************/ - -acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state) -{ - acpi_status status; - union acpi_operand_object **operand = &walk_state->operands[0]; - union acpi_operand_object *obj_desc; - struct acpi_namespace_node *node; - union acpi_operand_object *region_obj2; - acpi_native_uint table_index; - struct acpi_table_header *table; - - ACPI_FUNCTION_TRACE(ex_create_table_region); - - /* Get the Node from the object stack */ - - node = walk_state->op->common.node; - - /* - * If the region object is already attached to this node, - * just return - */ - if (acpi_ns_get_attached_object(node)) { - return_ACPI_STATUS(AE_OK); - } - - /* Find the ACPI table */ - - status = acpi_tb_find_table(operand[1]->string.pointer, - operand[2]->string.pointer, - operand[3]->string.pointer, &table_index); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Create the region descriptor */ - - obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION); - if (!obj_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - region_obj2 = obj_desc->common.next_object; - region_obj2->extra.region_context = NULL; - - status = acpi_get_table_by_index(table_index, &table); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Init the region from the operands */ - - obj_desc->region.space_id = REGION_DATA_TABLE; - obj_desc->region.address = - (acpi_physical_address) ACPI_TO_INTEGER(table); - obj_desc->region.length = table->length; - obj_desc->region.node = node; - obj_desc->region.flags = AOPOBJ_DATA_VALID; - - /* Install the new region object in the parent Node */ - - status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - status = acpi_ev_initialize_region(obj_desc, FALSE); - if (ACPI_FAILURE(status)) { - if (status == AE_NOT_EXIST) { - status = AE_OK; - } else { - goto cleanup; - } - } - - obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE; - - cleanup: - - /* Remove local reference to the object */ - - acpi_ut_remove_reference(obj_desc); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * * FUNCTION: acpi_ex_create_processor * * PARAMETERS: walk_state - Current state diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 51c9c29987c3..74f1b22601b3 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -500,25 +500,28 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) acpi_os_printf("Reference: Debug\n"); break; - case AML_NAME_OP: + case AML_INDEX_OP: - ACPI_DUMP_PATHNAME(obj_desc->reference.object, - "Reference: Name: ", ACPI_LV_INFO, - _COMPONENT); - ACPI_DUMP_ENTRY(obj_desc->reference.object, - ACPI_LV_INFO); + acpi_os_printf("Reference: Index %p\n", + obj_desc->reference.object); break; - case AML_INDEX_OP: + case AML_LOAD_OP: - acpi_os_printf("Reference: Index %p\n", + acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n", obj_desc->reference.object); break; case AML_REF_OF_OP: - acpi_os_printf("Reference: (RefOf) %p\n", - obj_desc->reference.object); + acpi_os_printf("Reference: (RefOf) %p [%s]\n", + obj_desc->reference.object, + acpi_ut_get_type_name(((union + acpi_operand_object + *)obj_desc-> + reference. + object)->common. + type)); break; case AML_ARG_OP: @@ -559,8 +562,9 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case AML_INT_NAMEPATH_OP: - acpi_os_printf("Reference.Node->Name %X\n", - obj_desc->reference.node->name.integer); + acpi_os_printf("Reference: Namepath %X [%4.4s]\n", + obj_desc->reference.node->name.integer, + obj_desc->reference.node->name.ascii); break; default: @@ -640,8 +644,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) acpi_os_printf("\n"); } else { acpi_os_printf(" base %8.8X%8.8X Length %X\n", - ACPI_FORMAT_UINT64(obj_desc->region. - address), + ACPI_FORMAT_NATIVE_UINT(obj_desc->region. + address), obj_desc->region.length); } break; @@ -877,20 +881,43 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER; if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) { - acpi_os_printf("Named Object %p ", obj_desc->reference.node); + acpi_os_printf(" Named Object %p ", obj_desc->reference.node); status = acpi_ns_handle_to_pathname(obj_desc->reference.node, &ret_buf); if (ACPI_FAILURE(status)) { - acpi_os_printf("Could not convert name to pathname\n"); + acpi_os_printf(" Could not convert name to pathname\n"); } else { acpi_os_printf("%s\n", (char *)ret_buf.pointer); ACPI_FREE(ret_buf.pointer); } } else if (obj_desc->reference.object) { - acpi_os_printf("\nReferenced Object: %p\n", - obj_desc->reference.object); + if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == + ACPI_DESC_TYPE_OPERAND) { + acpi_os_printf(" Target: %p", + obj_desc->reference.object); + if (obj_desc->reference.opcode == AML_LOAD_OP) { + /* + * For DDBHandle reference, + * obj_desc->Reference.Object is the table index + */ + acpi_os_printf(" [DDBHandle]\n"); + } else { + acpi_os_printf(" [%s]\n", + acpi_ut_get_type_name(((union + acpi_operand_object + *) + obj_desc-> + reference. + object)-> + common. + type)); + } + } else { + acpi_os_printf(" Target: %p\n", + obj_desc->reference.object); + } } } @@ -976,7 +1003,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, case ACPI_TYPE_LOCAL_REFERENCE: - acpi_os_printf("[Object Reference] "); + acpi_os_printf("[Object Reference] %s", + (acpi_ps_get_opcode_info + (obj_desc->reference.opcode))->name); acpi_ex_dump_reference_obj(obj_desc); break; diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index 2d88a3d8d1ad..3e440d84226a 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,7 +71,6 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; - u8 locked; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); @@ -111,9 +110,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, /* Lock entire transaction if requested */ - locked = - acpi_ex_acquire_global_lock(obj_desc->common_field. - field_flags); + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* * Perform the read. @@ -125,7 +122,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, buffer.pointer), ACPI_READ | (obj_desc->field. attribute << 16)); - acpi_ex_release_global_lock(locked); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } @@ -175,13 +172,12 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, /* Lock entire transaction if requested */ - locked = - acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Read from the field */ status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); - acpi_ex_release_global_lock(locked); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: if (ACPI_FAILURE(status)) { @@ -214,10 +210,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, { acpi_status status; u32 length; - u32 required_length; void *buffer; - void *new_buffer; - u8 locked; union acpi_operand_object *buffer_desc; ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); @@ -278,9 +271,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* Lock entire transaction if requested */ - locked = - acpi_ex_acquire_global_lock(obj_desc->common_field. - field_flags); + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* * Perform the write (returns status and perhaps data in the @@ -291,7 +282,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, (acpi_integer *) buffer, ACPI_WRITE | (obj_desc->field. attribute << 16)); - acpi_ex_release_global_lock(locked); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; return_ACPI_STATUS(status); @@ -319,35 +310,6 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* - * We must have a buffer that is at least as long as the field - * we are writing to. This is because individual fields are - * indivisible and partial writes are not supported -- as per - * the ACPI specification. - */ - new_buffer = NULL; - required_length = - ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); - - if (length < required_length) { - - /* We need to create a new buffer */ - - new_buffer = ACPI_ALLOCATE_ZEROED(required_length); - if (!new_buffer) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* - * Copy the original data to the new buffer, starting - * at Byte zero. All unused (upper) bytes of the - * buffer will be 0. - */ - ACPI_MEMCPY((char *)new_buffer, (char *)buffer, length); - buffer = new_buffer; - length = required_length; - } - ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", source_desc, @@ -366,19 +328,12 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* Lock entire transaction if requested */ - locked = - acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Write to the field */ status = acpi_ex_insert_into_field(obj_desc, buffer, length); - acpi_ex_release_global_lock(locked); - - /* Free temporary buffer if we used one */ - - if (new_buffer) { - ACPI_FREE(new_buffer); - } + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 65a48b6170ee..e336b5dc7a50 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -263,7 +263,8 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, rgn_desc->region.space_id, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, - field_datum_byte_offset, (void *)address)); + field_datum_byte_offset, ACPI_CAST_PTR(void, + address))); /* Invoke the appropriate address_space/op_region handler */ @@ -805,18 +806,39 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, u32 datum_count; u32 field_datum_count; u32 i; + u32 required_length; + void *new_buffer; ACPI_FUNCTION_TRACE(ex_insert_into_field); /* Validate input buffer */ - if (buffer_length < - ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) { - ACPI_ERROR((AE_INFO, - "Field size %X (bits) is too large for buffer (%X)", - obj_desc->common_field.bit_length, buffer_length)); + new_buffer = NULL; + required_length = + ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); + /* + * We must have a buffer that is at least as long as the field + * we are writing to. This is because individual fields are + * indivisible and partial writes are not supported -- as per + * the ACPI specification. + */ + if (buffer_length < required_length) { - return_ACPI_STATUS(AE_BUFFER_OVERFLOW); + /* We need to create a new buffer */ + + new_buffer = ACPI_ALLOCATE_ZEROED(required_length); + if (!new_buffer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* + * Copy the original data to the new buffer, starting + * at Byte zero. All unused (upper) bytes of the + * buffer will be 0. + */ + ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length); + buffer = new_buffer; + buffer_length = required_length; } /* @@ -866,7 +888,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, merged_datum, field_offset); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto exit; } field_offset += obj_desc->common_field.access_byte_width; @@ -924,5 +946,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, mask, merged_datum, field_offset); + exit: + /* Free temporary buffer if we used one */ + + if (new_buffer) { + ACPI_FREE(new_buffer); + } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index f13d1cec2d6d..cc956a5b5267 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 6748e3ef0997..c873ab40cd0e 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -126,6 +126,79 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc, /******************************************************************************* * + * FUNCTION: acpi_ex_acquire_mutex_object + * + * PARAMETERS: time_desc - Timeout in milliseconds + * obj_desc - Mutex object + * Thread - Current thread state + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common + * path that supports multiple acquires by the same thread. + * + * MUTEX: Interpreter must be locked + * + * NOTE: This interface is called from three places: + * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator + * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the + * global lock + * 3) From the external interface, acpi_acquire_global_lock + * + ******************************************************************************/ + +acpi_status +acpi_ex_acquire_mutex_object(u16 timeout, + union acpi_operand_object *obj_desc, + acpi_thread_id thread_id) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc); + + if (!obj_desc) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + /* Support for multiple acquires by the owning thread */ + + if (obj_desc->mutex.thread_id == thread_id) { + /* + * The mutex is already owned by this thread, just increment the + * acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS(AE_OK); + } + + /* Acquire the mutex, wait if necessary. Special case for Global Lock */ + + if (obj_desc == acpi_gbl_global_lock_mutex) { + status = acpi_ev_acquire_global_lock(timeout); + } else { + status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, + timeout); + } + + if (ACPI_FAILURE(status)) { + + /* Includes failure from a timeout on time_desc */ + + return_ACPI_STATUS(status); + } + + /* Acquired the mutex: update mutex object */ + + obj_desc->mutex.thread_id = thread_id; + obj_desc->mutex.acquisition_depth = 1; + obj_desc->mutex.original_sync_level = 0; + obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */ + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * * FUNCTION: acpi_ex_acquire_mutex * * PARAMETERS: time_desc - Timeout integer @@ -151,7 +224,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Sanity check: we must have a valid thread ID */ + /* Must have a valid thread ID */ if (!walk_state->thread) { ACPI_ERROR((AE_INFO, @@ -161,7 +234,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, } /* - * Current Sync must be less than or equal to the sync level of the + * Current sync level must be less than or equal to the sync level of the * mutex. This mechanism provides some deadlock prevention */ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { @@ -172,51 +245,89 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } - /* Support for multiple acquires by the owning thread */ + status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value, + obj_desc, + walk_state->thread->thread_id); + if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { - if (obj_desc->mutex.owner_thread) { - if (obj_desc->mutex.owner_thread->thread_id == - walk_state->thread->thread_id) { - /* - * The mutex is already owned by this thread, just increment the - * acquisition depth - */ - obj_desc->mutex.acquisition_depth++; - return_ACPI_STATUS(AE_OK); - } + /* Save Thread object, original/current sync levels */ + + obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.original_sync_level = + walk_state->thread->current_sync_level; + walk_state->thread->current_sync_level = + obj_desc->mutex.sync_level; + + /* Link the mutex to the current thread for force-unlock at method exit */ + + acpi_ex_link_mutex(obj_desc, walk_state->thread); } - /* Acquire the mutex, wait if necessary. Special case for Global Lock */ + return_ACPI_STATUS(status); +} - if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { - status = - acpi_ev_acquire_global_lock((u16) time_desc->integer.value); - } else { - status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, - (u16) time_desc->integer. - value); +/******************************************************************************* + * + * FUNCTION: acpi_ex_release_mutex_object + * + * PARAMETERS: obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Release a previously acquired Mutex, low level interface. + * Provides a common path that supports multiple releases (after + * previous multiple acquires) by the same thread. + * + * MUTEX: Interpreter must be locked + * + * NOTE: This interface is called from three places: + * 1) From acpi_ex_release_mutex, via an AML Acquire() operator + * 2) From acpi_ex_release_global_lock when an AML Field access requires the + * global lock + * 3) From the external interface, acpi_release_global_lock + * + ******************************************************************************/ + +acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE(ex_release_mutex_object); + + if (obj_desc->mutex.acquisition_depth == 0) { + return (AE_NOT_ACQUIRED); } - if (ACPI_FAILURE(status)) { + /* Match multiple Acquires with multiple Releases */ - /* Includes failure from a timeout on time_desc */ + obj_desc->mutex.acquisition_depth--; + if (obj_desc->mutex.acquisition_depth != 0) { - return_ACPI_STATUS(status); + /* Just decrement the depth and return */ + + return_ACPI_STATUS(AE_OK); } - /* Have the mutex: update mutex and walk info and save the sync_level */ + if (obj_desc->mutex.owner_thread) { - obj_desc->mutex.owner_thread = walk_state->thread; - obj_desc->mutex.acquisition_depth = 1; - obj_desc->mutex.original_sync_level = - walk_state->thread->current_sync_level; + /* Unlink the mutex from the owner's list */ - walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; + acpi_ex_unlink_mutex(obj_desc); + obj_desc->mutex.owner_thread = NULL; + } - /* Link the mutex to the current thread for force-unlock at method exit */ + /* Release the mutex, special case for Global Lock */ - acpi_ex_link_mutex(obj_desc, walk_state->thread); - return_ACPI_STATUS(AE_OK); + if (obj_desc == acpi_gbl_global_lock_mutex) { + status = acpi_ev_release_global_lock(); + } else { + acpi_os_release_mutex(obj_desc->mutex.os_mutex); + } + + /* Clear mutex info */ + + obj_desc->mutex.thread_id = 0; + return_ACPI_STATUS(status); } /******************************************************************************* @@ -253,22 +364,13 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); } - /* Sanity check: we must have a valid thread ID */ - - if (!walk_state->thread) { - ACPI_ERROR((AE_INFO, - "Cannot release Mutex [%4.4s], null thread info", - acpi_ut_get_node_name(obj_desc->mutex.node))); - return_ACPI_STATUS(AE_AML_INTERNAL); - } - /* * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release */ if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) - && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { + && (obj_desc != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, @@ -278,45 +380,37 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_NOT_OWNER); } + /* Must have a valid thread ID */ + + if (!walk_state->thread) { + ACPI_ERROR((AE_INFO, + "Cannot release Mutex [%4.4s], null thread info", + acpi_ut_get_node_name(obj_desc->mutex.node))); + return_ACPI_STATUS(AE_AML_INTERNAL); + } + /* * The sync level of the mutex must be less than or equal to the current * sync level */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, - "Cannot release Mutex [%4.4s], incorrect SyncLevel", - acpi_ut_get_node_name(obj_desc->mutex.node))); + "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", + acpi_ut_get_node_name(obj_desc->mutex.node), + obj_desc->mutex.sync_level, + walk_state->thread->current_sync_level)); return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } - /* Match multiple Acquires with multiple Releases */ - - obj_desc->mutex.acquisition_depth--; - if (obj_desc->mutex.acquisition_depth != 0) { - - /* Just decrement the depth and return */ - - return_ACPI_STATUS(AE_OK); - } - - /* Unlink the mutex from the owner's list */ + status = acpi_ex_release_mutex_object(obj_desc); - acpi_ex_unlink_mutex(obj_desc); + if (obj_desc->mutex.acquisition_depth == 0) { - /* Release the mutex, special case for Global Lock */ + /* Restore the original sync_level */ - if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { - status = acpi_ev_release_global_lock(); - } else { - acpi_os_release_mutex(obj_desc->mutex.os_mutex); + walk_state->thread->current_sync_level = + obj_desc->mutex.original_sync_level; } - - /* Update the mutex and restore sync_level */ - - obj_desc->mutex.owner_thread = NULL; - walk_state->thread->current_sync_level = - obj_desc->mutex.original_sync_level; - return_ACPI_STATUS(status); } @@ -357,7 +451,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) /* Release the mutex, special case for Global Lock */ - if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + if (obj_desc == acpi_gbl_global_lock_mutex) { /* Ignore errors */ @@ -369,6 +463,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) /* Mark mutex unowned */ obj_desc->mutex.owner_thread = NULL; + obj_desc->mutex.thread_id = 0; /* Update Thread sync_level (Last mutex is the important one) */ diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 308eae52dc05..817e67be3697 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 252f10acbbcc..7c3bea575e02 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -121,6 +121,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) if ((ACPI_FAILURE(status)) || walk_state->result_obj) { acpi_ut_remove_reference(return_desc); + walk_state->result_obj = NULL; } else { /* Save the return value */ @@ -739,26 +740,38 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) value = acpi_gbl_integer_byte_width; break; - case ACPI_TYPE_BUFFER: - value = temp_desc->buffer.length; - break; - case ACPI_TYPE_STRING: value = temp_desc->string.length; break; + case ACPI_TYPE_BUFFER: + + /* Buffer arguments may not be evaluated at this point */ + + status = acpi_ds_get_buffer_arguments(temp_desc); + value = temp_desc->buffer.length; + break; + case ACPI_TYPE_PACKAGE: + + /* Package arguments may not be evaluated at this point */ + + status = acpi_ds_get_package_arguments(temp_desc); value = temp_desc->package.count; break; default: ACPI_ERROR((AE_INFO, - "Operand is not Buf/Int/Str/Pkg - found type %s", + "Operand must be Buffer/Integer/String/Package - found type %s", acpi_ut_get_type_name(type))); status = AE_AML_OPERAND_TYPE; goto cleanup; } + if (ACPI_FAILURE(status)) { + goto cleanup; + } + /* * Now that we have the size of the object, create a result * object to hold the value diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 17e652e65379..8e8bbb6ccebd 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -241,10 +241,6 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) goto cleanup; } - /* Return the remainder */ - - walk_state->result_obj = return_desc1; - cleanup: /* * Since the remainder is not returned indirectly, remove a reference to @@ -259,6 +255,12 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) acpi_ut_remove_reference(return_desc1); } + /* Save return object (the remainder) on success */ + + else { + walk_state->result_obj = return_desc1; + } + return_ACPI_STATUS(status); } @@ -490,6 +492,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); + walk_state->result_obj = NULL; } return_ACPI_STATUS(status); @@ -583,8 +586,6 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) return_desc->integer.value = ACPI_INTEGER_MAX; } - walk_state->result_obj = return_desc; - cleanup: /* Delete return object on error */ @@ -593,5 +594,11 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) acpi_ut_remove_reference(return_desc); } + /* Save return object on success */ + + else { + walk_state->result_obj = return_desc; + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index 7fe67cf82cee..9cb4197681af 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -260,6 +260,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status) || walk_state->result_obj) { acpi_ut_remove_reference(return_desc); + walk_state->result_obj = NULL; } /* Set the return object and exit */ diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index bd80a9cb3d65..67d48737af53 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -322,8 +322,6 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) goto cleanup; } - walk_state->result_obj = return_desc; - cleanup: /* Delete return object on error */ @@ -332,5 +330,11 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) acpi_ut_remove_reference(return_desc); } + /* Save return object on success */ + + else { + walk_state->result_obj = return_desc; + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index efe5d4b461a4..3a2f8cd4c62a 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -412,6 +412,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { union acpi_operand_object *obj_desc; + union acpi_operand_object *second_desc = NULL; u32 type; acpi_status status; @@ -494,6 +495,20 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj, obj_desc->bank_field.bank_obj)); + + /* + * Remember location in AML stream of the field unit + * opcode and operands -- since the bank_value + * operands must be evaluated. + */ + second_desc = obj_desc->common.next_object; + second_desc->extra.aml_start = + ((union acpi_parse_object *)(info->data_register_node))-> + named.data; + second_desc->extra.aml_length = + ((union acpi_parse_object *)(info->data_register_node))-> + named.length; + break; case ACPI_TYPE_LOCAL_INDEX_FIELD: diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 3f51b7e84a17..7cd8bb54fa01 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -160,7 +160,7 @@ acpi_ex_system_memory_space_handler(u32 function, if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at %8.8X%8.8X, size %X", - ACPI_FORMAT_UINT64(address), + ACPI_FORMAT_NATIVE_UINT(address), (u32) window_size)); mem_info->mapped_length = 0; return_ACPI_STATUS(AE_NO_MEMORY); @@ -182,7 +182,8 @@ acpi_ex_system_memory_space_handler(u32 function, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n", - bit_width, function, ACPI_FORMAT_UINT64(address))); + bit_width, function, + ACPI_FORMAT_NATIVE_UINT(address))); /* * Perform the memory read or write @@ -284,7 +285,8 @@ acpi_ex_system_io_space_handler(u32 function, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-IO (width %d) R/W %d Address=%8.8X%8.8X\n", - bit_width, function, ACPI_FORMAT_UINT64(address))); + bit_width, function, + ACPI_FORMAT_NATIVE_UINT(address))); /* Decode the function parameter */ diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 2b3a01cc4929..5596f42c9676 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -116,9 +116,11 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, * Several object types require no further processing: * 1) Device/Thermal objects don't have a "real" subobject, return the Node * 2) Method locals and arguments have a pseudo-Node + * 3) 10/2007: Added method type to assist with Package construction. */ if ((entry_type == ACPI_TYPE_DEVICE) || (entry_type == ACPI_TYPE_THERMAL) || + (entry_type == ACPI_TYPE_METHOD) || (node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) { return_ACPI_STATUS(AE_OK); } @@ -214,7 +216,6 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, /* For these objects, just return the object attached to the Node */ case ACPI_TYPE_MUTEX: - case ACPI_TYPE_METHOD: case ACPI_TYPE_POWER: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_EVENT: @@ -238,13 +239,12 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, case ACPI_TYPE_LOCAL_REFERENCE: switch (source_desc->reference.opcode) { - case AML_LOAD_OP: + case AML_LOAD_OP: /* This is a ddb_handle */ + case AML_REF_OF_OP: + case AML_INDEX_OP: - /* This is a ddb_handle */ /* Return an additional reference to the object */ - case AML_REF_OF_OP: - obj_desc = source_desc; acpi_ut_add_reference(obj_desc); break; diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 6c64e55dab0e..b35f7c817acf 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -140,7 +140,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, { acpi_status status = AE_OK; union acpi_operand_object *stack_desc; - void *temp_node; union acpi_operand_object *obj_desc = NULL; u16 opcode; @@ -156,23 +155,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, opcode = stack_desc->reference.opcode; switch (opcode) { - case AML_NAME_OP: - - /* - * Convert name reference to a namespace node - * Then, acpi_ex_resolve_node_to_value can be used to get the value - */ - temp_node = stack_desc->reference.object; - - /* Delete the Reference Object */ - - acpi_ut_remove_reference(stack_desc); - - /* Return the namespace node */ - - (*stack_ptr) = temp_node; - break; - case AML_LOCAL_OP: case AML_ARG_OP: @@ -207,15 +189,25 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, switch (stack_desc->reference.target_type) { case ACPI_TYPE_BUFFER_FIELD: - /* Just return - leave the Reference on the stack */ + /* Just return - do not dereference */ break; case ACPI_TYPE_PACKAGE: + /* If method call or copy_object - do not dereference */ + + if ((walk_state->opcode == + AML_INT_METHODCALL_OP) + || (walk_state->opcode == AML_COPY_OP)) { + break; + } + + /* Otherwise, dereference the package_index to a package element */ + obj_desc = *stack_desc->reference.where; if (obj_desc) { /* - * Valid obj descriptor, copy pointer to return value + * Valid object descriptor, copy pointer to return value * (i.e., dereference the package index) * Delete the ref object, increment the returned object */ @@ -224,11 +216,11 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, *stack_ptr = obj_desc; } else { /* - * A NULL object descriptor means an unitialized element of + * A NULL object descriptor means an uninitialized element of * the package, can't dereference it */ ACPI_ERROR((AE_INFO, - "Attempt to deref an Index to NULL pkg element Idx=%p", + "Attempt to dereference an Index to NULL package element Idx=%p", stack_desc)); status = AE_AML_UNINITIALIZED_ELEMENT; } @@ -239,7 +231,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, /* Invalid reference object */ ACPI_ERROR((AE_INFO, - "Unknown TargetType %X in Index/Reference obj %p", + "Unknown TargetType %X in Index/Reference object %p", stack_desc->reference.target_type, stack_desc)); status = AE_AML_INTERNAL; @@ -251,7 +243,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, case AML_DEBUG_OP: case AML_LOAD_OP: - /* Just leave the object as-is */ + /* Just leave the object as-is, do not dereference */ break; @@ -390,10 +382,10 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, } /* - * For reference objects created via the ref_of or Index operators, - * we need to get to the base object (as per the ACPI specification - * of the object_type and size_of operators). This means traversing - * the list of possibly many nested references. + * For reference objects created via the ref_of, Index, or Load/load_table + * operators, we need to get to the base object (as per the ACPI + * specification of the object_type and size_of operators). This means + * traversing the list of possibly many nested references. */ while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) { switch (obj_desc->reference.opcode) { @@ -463,6 +455,11 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, } break; + case AML_LOAD_OP: + + type = ACPI_TYPE_DDB_HANDLE; + goto exit; + case AML_LOCAL_OP: case AML_ARG_OP: diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index 09d897b3f6d5..73e29e566a70 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -137,7 +137,6 @@ acpi_ex_resolve_operands(u16 opcode, union acpi_operand_object *obj_desc; acpi_status status = AE_OK; u8 object_type; - void *temp_node; u32 arg_types; const struct acpi_opcode_info *op_info; u32 this_arg_type; @@ -239,7 +238,6 @@ acpi_ex_resolve_operands(u16 opcode, /*lint -fallthrough */ - case AML_NAME_OP: case AML_INDEX_OP: case AML_REF_OF_OP: case AML_ARG_OP: @@ -332,15 +330,6 @@ acpi_ex_resolve_operands(u16 opcode, if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - - if (obj_desc->reference.opcode == AML_NAME_OP) { - - /* Convert a named reference to the actual named object */ - - temp_node = obj_desc->reference.object; - acpi_ut_remove_reference(obj_desc); - (*stack_ptr) = temp_node; - } goto next_operand; case ARGI_DATAREFOBJ: /* Store operator only */ diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index f4b69a637820..76c875bc3154 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -84,8 +84,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc); - ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s", - level, " ")); + /* Print line header as long as we are not in the middle of an object display */ + + if (!((level > 0) && index == 0)) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s", + level, " ")); + } /* Display index for package output only */ @@ -95,12 +99,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, } if (!source_desc) { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "<Null Object>\n")); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[Null Object]\n")); return_VOID; } if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s: ", + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s ", acpi_ut_get_object_type_name (source_desc))); @@ -123,6 +127,8 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, return_VOID; } + /* source_desc is of type ACPI_DESC_TYPE_OPERAND */ + switch (ACPI_GET_OBJECT_TYPE(source_desc)) { case ACPI_TYPE_INTEGER: @@ -147,7 +153,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, (u32) source_desc->buffer.length)); ACPI_DUMP_BUFFER(source_desc->buffer.pointer, (source_desc->buffer.length < - 32) ? source_desc->buffer.length : 32); + 256) ? source_desc->buffer.length : 256); break; case ACPI_TYPE_STRING: @@ -160,7 +166,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_TYPE_PACKAGE: ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, - "[0x%.2X Elements]\n", + "[Contains 0x%.2X Elements]\n", source_desc->package.count)); /* Output the entire contents of the package */ @@ -180,12 +186,59 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, (source_desc->reference.opcode), source_desc->reference.offset)); } else { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]\n", + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]", acpi_ps_get_opcode_name (source_desc->reference.opcode))); } - if (source_desc->reference.object) { + if (source_desc->reference.opcode == AML_LOAD_OP) { /* Load and load_table */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, + " Table OwnerId %p\n", + source_desc->reference.object)); + break; + } + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, " ")); + + /* Check for valid node first, then valid object */ + + if (source_desc->reference.node) { + if (ACPI_GET_DESCRIPTOR_TYPE + (source_desc->reference.node) != + ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, + " %p - Not a valid namespace node\n", + source_desc->reference. + node)); + } else { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, + "Node %p [%4.4s] ", + source_desc->reference. + node, + (source_desc->reference. + node)->name.ascii)); + + switch ((source_desc->reference.node)->type) { + + /* These types have no attached object */ + + case ACPI_TYPE_DEVICE: + acpi_os_printf("Device\n"); + break; + + case ACPI_TYPE_THERMAL: + acpi_os_printf("Thermal Zone\n"); + break; + + default: + acpi_ex_do_debug_object((source_desc-> + reference. + node)->object, + level + 4, 0); + break; + } + } + } else if (source_desc->reference.object) { if (ACPI_GET_DESCRIPTOR_TYPE (source_desc->reference.object) == ACPI_DESC_TYPE_NAMED) { @@ -198,18 +251,13 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, acpi_ex_do_debug_object(source_desc->reference. object, level + 4, 0); } - } else if (source_desc->reference.node) { - acpi_ex_do_debug_object((source_desc->reference.node)-> - object, level + 4, 0); } break; default: - ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p %s\n", - source_desc, - acpi_ut_get_object_type_name - (source_desc))); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p\n", + source_desc)); break; } @@ -313,7 +361,6 @@ acpi_ex_store(union acpi_operand_object *source_desc, * 4) Store to the debug object */ switch (ref_desc->reference.opcode) { - case AML_NAME_OP: case AML_REF_OF_OP: /* Storing an object into a Name "container" */ @@ -415,11 +462,24 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, */ obj_desc = *(index_desc->reference.where); - status = - acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, - walk_state); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + if (ACPI_GET_OBJECT_TYPE(source_desc) == + ACPI_TYPE_LOCAL_REFERENCE + && source_desc->reference.opcode == AML_LOAD_OP) { + + /* This is a DDBHandle, just add a reference to it */ + + acpi_ut_add_reference(source_desc); + new_desc = source_desc; + } else { + /* Normal object, copy it */ + + status = + acpi_ut_copy_iobject_to_iobject(source_desc, + &new_desc, + walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } } if (obj_desc) { @@ -571,10 +631,17 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, /* If no implicit conversion, drop into the default case below */ - if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) { - - /* Force execution of default (no implicit conversion) */ - + if ((!implicit_conversion) || + ((walk_state->opcode == AML_COPY_OP) && + (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) && + (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) && + (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) { + /* + * Force execution of default (no implicit conversion). Note: + * copy_object does not perform an implicit conversion, as per the ACPI + * spec -- except in case of region/bank/index fields -- because these + * objects must retain their original type permanently. + */ target_type = ACPI_TYPE_ANY; } diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index 1d622c625c64..a6d2168b81f9 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 8233d40178ee..9a75ff09fb0c 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index 9460baff3032..68990f1df371 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,7 +44,6 @@ #include <acpi/acpi.h> #include <acpi/acinterp.h> -#include <acpi/acevents.h> #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exsystem") diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 6b0aeccbb69b..86c03880b523 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,7 +61,6 @@ #include <acpi/acpi.h> #include <acpi/acinterp.h> #include <acpi/amlcode.h> -#include <acpi/acevents.h> #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exutils") @@ -217,9 +216,10 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc) /* * Object must be a valid number and we must be executing - * a control method + * a control method. NS node could be there for AML_INT_NAMEPATH_OP. */ if ((!obj_desc) || + (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) || (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) { return; } @@ -240,72 +240,73 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc) * PARAMETERS: field_flags - Flags with Lock rule: * always_lock or never_lock * - * RETURN: TRUE/FALSE indicating whether the lock was actually acquired + * RETURN: None * - * DESCRIPTION: Obtain the global lock and keep track of this fact via two - * methods. A global variable keeps the state of the lock, and - * the state is returned to the caller. + * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field + * flags specifiy that it is to be obtained before field access. * ******************************************************************************/ -u8 acpi_ex_acquire_global_lock(u32 field_flags) +void acpi_ex_acquire_global_lock(u32 field_flags) { - u8 locked = FALSE; acpi_status status; ACPI_FUNCTION_TRACE(ex_acquire_global_lock); - /* Only attempt lock if the always_lock bit is set */ + /* Only use the lock if the always_lock bit is set */ + + if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) { + return_VOID; + } - if (field_flags & AML_FIELD_LOCK_RULE_MASK) { + /* Attempt to get the global lock, wait forever */ - /* We should attempt to get the lock, wait forever */ + status = acpi_ex_acquire_mutex_object(ACPI_WAIT_FOREVER, + acpi_gbl_global_lock_mutex, + acpi_os_get_thread_id()); - status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER); - if (ACPI_SUCCESS(status)) { - locked = TRUE; - } else { - ACPI_EXCEPTION((AE_INFO, status, - "Could not acquire Global Lock")); - } + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Could not acquire Global Lock")); } - return_UINT8(locked); + return_VOID; } /******************************************************************************* * * FUNCTION: acpi_ex_release_global_lock * - * PARAMETERS: locked_by_me - Return value from corresponding call to - * acquire_global_lock. + * PARAMETERS: field_flags - Flags with Lock rule: + * always_lock or never_lock * * RETURN: None * - * DESCRIPTION: Release the global lock if it is locked. + * DESCRIPTION: Release the ACPI hardware Global Lock * ******************************************************************************/ -void acpi_ex_release_global_lock(u8 locked_by_me) +void acpi_ex_release_global_lock(u32 field_flags) { acpi_status status; ACPI_FUNCTION_TRACE(ex_release_global_lock); - /* Only attempt unlock if the caller locked it */ + /* Only use the lock if the always_lock bit is set */ - if (locked_by_me) { + if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) { + return_VOID; + } - /* OK, now release the lock */ + /* Release the global lock */ - status = acpi_ev_release_global_lock(); - if (ACPI_FAILURE(status)) { + status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex); + if (ACPI_FAILURE(status)) { - /* Report the error, but there isn't much else we can do */ + /* Report the error, but there isn't much else we can do */ - ACPI_EXCEPTION((AE_INFO, status, - "Could not release ACPI Global Lock")); - } + ACPI_EXCEPTION((AE_INFO, status, + "Could not release Global Lock")); } return_VOID; diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index c8e3cba423ef..6cf10cbc1eee 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -192,17 +192,13 @@ static int acpi_fan_add_fs(struct acpi_device *device) } /* 'status' [R/W] */ - entry = create_proc_entry(ACPI_FAN_FILE_STATE, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_FAN_FILE_STATE, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_fan_state_ops, + device); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_fan_state_ops; - entry->data = device; - entry->owner = THIS_MODULE; - } - return 0; } @@ -260,24 +256,23 @@ static int acpi_fan_add(struct acpi_device *device) result = PTR_ERR(cdev); goto end; } - if (cdev) { - printk(KERN_INFO PREFIX - "%s is registered as cooling_device%d\n", - device->dev.bus_id, cdev->id); - - acpi_driver_data(device) = cdev; - result = sysfs_create_link(&device->dev.kobj, - &cdev->device.kobj, - "thermal_cooling"); - if (result) - return result; - - result = sysfs_create_link(&cdev->device.kobj, - &device->dev.kobj, - "device"); - if (result) - return result; - } + + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev.bus_id, cdev->id); + + acpi_driver_data(device) = cdev; + result = sysfs_create_link(&device->dev.kobj, + &cdev->device.kobj, + "thermal_cooling"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + + result = sysfs_create_link(&cdev->device.kobj, + &device->dev.kobj, + "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); result = acpi_fan_add_fs(device); if (result) diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index eda0978b57c6..06f8634fe58b 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -142,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device); static int acpi_bind_one(struct device *dev, acpi_handle handle) { + struct acpi_device *acpi_dev; acpi_status status; if (dev->archdata.acpi_handle) { @@ -157,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) } dev->archdata.acpi_handle = handle; + status = acpi_bus_get_device(handle, &acpi_dev); + if (!ACPI_FAILURE(status)) { + int ret; + + ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, + "firmware_node"); + ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, + "physical_node"); + } + return 0; } @@ -165,8 +176,17 @@ static int acpi_unbind_one(struct device *dev) if (!dev->archdata.acpi_handle) return 0; if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { + struct acpi_device *acpi_dev; + /* acpi_get_physical_device increase refcnt by one */ put_device(dev); + + if (!acpi_bus_get_device(dev->archdata.acpi_handle, + &acpi_dev)) { + sysfs_remove_link(&dev->kobj, "firmware_node"); + sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node"); + } + acpi_detach_data(dev->archdata.acpi_handle, acpi_glue_data_handler); dev->archdata.acpi_handle = NULL; diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index 6031ca13dd2f..816894ea839e 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 117a05cadaaa..14bc4f456ae8 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 73f9c5fb1ba7..ddf792adcf96 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 4290e0193097..d9937e05ec6a 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,9 +70,10 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address) /* Get the FACS */ - status = - acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - (struct acpi_table_header **)&facs); + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -124,9 +125,10 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) /* Get the FACS */ - status = - acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - (struct acpi_table_header **)&facs); + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index c32eab696acd..b53d575491b9 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 57faf598bad8..c39a7f68b889 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -208,8 +208,7 @@ acpi_status acpi_ns_root_initialize(void) /* Special case for ACPI Global Lock */ if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { - acpi_gbl_global_lock_mutex = - obj_desc->mutex.os_mutex; + acpi_gbl_global_lock_mutex = obj_desc; /* Create additional counting semaphore for global lock */ @@ -582,44 +581,68 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, return_ACPI_STATUS(status); } - /* - * Sanity typecheck of the target object: - * - * If 1) This is the last segment (num_segments == 0) - * 2) And we are looking for a specific type - * (Not checking for TYPE_ANY) - * 3) Which is not an alias - * 4) Which is not a local type (TYPE_SCOPE) - * 5) And the type of target object is known (not TYPE_ANY) - * 6) And target object does not match what we are looking for - * - * Then we have a type mismatch. Just warn and ignore it. - */ - if ((num_segments == 0) && - (type_to_check_for != ACPI_TYPE_ANY) && - (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && - (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && - (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && - (this_node->type != ACPI_TYPE_ANY) && - (this_node->type != type_to_check_for)) { - - /* Complain about a type mismatch */ - - ACPI_WARNING((AE_INFO, - "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", - ACPI_CAST_PTR(char, &simple_name), - acpi_ut_get_type_name(this_node->type), - acpi_ut_get_type_name - (type_to_check_for))); + /* More segments to follow? */ + + if (num_segments > 0) { + /* + * If we have an alias to an object that opens a scope (such as a + * device or processor), we need to dereference the alias here so that + * we can access any children of the original node (via the remaining + * segments). + */ + if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { + if (acpi_ns_opens_scope + (((struct acpi_namespace_node *)this_node-> + object)->type)) { + this_node = + (struct acpi_namespace_node *) + this_node->object; + } + } } - /* - * If this is the last name segment and we are not looking for a - * specific type, but the type of found object is known, use that type - * to see if it opens a scope. - */ - if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) { - type = this_node->type; + /* Special handling for the last segment (num_segments == 0) */ + + else { + /* + * Sanity typecheck of the target object: + * + * If 1) This is the last segment (num_segments == 0) + * 2) And we are looking for a specific type + * (Not checking for TYPE_ANY) + * 3) Which is not an alias + * 4) Which is not a local type (TYPE_SCOPE) + * 5) And the type of target object is known (not TYPE_ANY) + * 6) And target object does not match what we are looking for + * + * Then we have a type mismatch. Just warn and ignore it. + */ + if ((type_to_check_for != ACPI_TYPE_ANY) && + (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && + (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) + && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) + && (this_node->type != ACPI_TYPE_ANY) + && (this_node->type != type_to_check_for)) { + + /* Complain about a type mismatch */ + + ACPI_WARNING((AE_INFO, + "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", + ACPI_CAST_PTR(char, &simple_name), + acpi_ut_get_type_name(this_node-> + type), + acpi_ut_get_type_name + (type_to_check_for))); + } + + /* + * If this is the last name segment and we are not looking for a + * specific type, but the type of found object is known, use that type + * to (later) see if it opens a scope. + */ + if (type == ACPI_TYPE_ANY) { + type = this_node->type; + } } /* Point to next name segment and make this node current */ diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index 1d693d8ad2d8..3a1740ac2edc 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index 1fc4f86676e1..5445751b8a3e 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -249,7 +249,9 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, acpi_os_printf("ID %X Len %.4X Addr %p\n", obj_desc->processor.proc_id, obj_desc->processor.length, - (char *)obj_desc->processor.address); + ACPI_CAST_PTR(void, + obj_desc->processor. + address)); break; case ACPI_TYPE_DEVICE: @@ -320,9 +322,8 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n", - ACPI_FORMAT_UINT64(obj_desc-> - region. - address), + ACPI_FORMAT_NATIVE_UINT + (obj_desc->region.address), obj_desc->region.length); } else { acpi_os_printf diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index 5097e167939e..428f50fde11a 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 97b2ac57c16b..14bdfa92bea0 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 33db2241044e..6d6d930c8e18 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -244,6 +244,10 @@ acpi_ns_init_one_object(acpi_handle obj_handle, info->field_count++; break; + case ACPI_TYPE_LOCAL_BANK_FIELD: + info->field_count++; + break; + case ACPI_TYPE_BUFFER: info->buffer_count++; break; @@ -287,6 +291,12 @@ acpi_ns_init_one_object(acpi_handle obj_handle, status = acpi_ds_get_buffer_field_arguments(obj_desc); break; + case ACPI_TYPE_LOCAL_BANK_FIELD: + + info->field_init++; + status = acpi_ds_get_bank_field_arguments(obj_desc); + break; + case ACPI_TYPE_BUFFER: info->buffer_init++; diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index d4f9654fd20f..2c92f6cf5ce1 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -107,11 +107,11 @@ acpi_ns_load_table(acpi_native_uint table_index, goto unlock; } - status = acpi_ns_parse_table(table_index, node->child); + status = acpi_ns_parse_table(table_index, node); if (ACPI_SUCCESS(status)) { acpi_tb_set_table_loaded_flag(table_index, TRUE); } else { - acpi_tb_release_owner_id(table_index); + (void)acpi_tb_release_owner_id(table_index); } unlock: diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index cbd94af08cc5..cffef1bcbdbc 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -180,6 +180,12 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) next_node = node; while (next_node && (next_node != acpi_gbl_root_node)) { + if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) { + ACPI_ERROR((AE_INFO, + "Invalid NS Node (%p) while traversing path", + next_node)); + return 0; + } size += ACPI_PATH_SEGMENT_LENGTH; next_node = acpi_ns_get_parent_node(next_node); } diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index d9d7377bc6e6..15fe09e24f71 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c index e696aa847990..46a79b0103b6 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/namespace/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,7 +64,8 @@ ACPI_MODULE_NAME("nsparse") ******************************************************************************/ acpi_status acpi_ns_one_complete_parse(acpi_native_uint pass_number, - acpi_native_uint table_index) + acpi_native_uint table_index, + struct acpi_namespace_node * start_node) { union acpi_parse_object *parse_root; acpi_status status; @@ -111,14 +112,25 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number, aml_start = (u8 *) table + sizeof(struct acpi_table_header); aml_length = table->length - sizeof(struct acpi_table_header); status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, - aml_start, aml_length, NULL, - (u8) pass_number); + aml_start, (u32) aml_length, + NULL, (u8) pass_number); } if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); - acpi_ps_delete_parse_tree(parse_root); - return_ACPI_STATUS(status); + goto cleanup; + } + + /* start_node is the default location to load the table */ + + if (start_node && start_node != acpi_gbl_root_node) { + status = + acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD, + walk_state); + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } } /* Parse the AML */ @@ -127,6 +139,7 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number, (unsigned)pass_number)); status = acpi_ps_parse_aml(walk_state); + cleanup: acpi_ps_delete_parse_tree(parse_root); return_ACPI_STATUS(status); } @@ -163,7 +176,9 @@ acpi_ns_parse_table(acpi_native_uint table_index, * performs another complete parse of the AML. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); - status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index); + status = + acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index, + start_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -178,7 +193,9 @@ acpi_ns_parse_table(acpi_native_uint table_index, * parse objects are all cached. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n")); - status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index); + status = + acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index, + start_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index e863be665ce8..8399276cba1e 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 90fd059615ff..64c039843ed2 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index 280b8357c46c..3c905ce26d7d 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,9 +77,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct /* It's really the parent's _scope_ that we want */ - if (parent_node->child) { - next_node = parent_node->child; - } + next_node = parent_node->child; } else { diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index b92133faf5b7..a8d549187c84 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -467,10 +467,13 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, return (AE_CTRL_DEPTH); } - if (!(flags & ACPI_STA_DEVICE_PRESENT)) { - - /* Don't examine children of the device if not present */ - + if (!(flags & ACPI_STA_DEVICE_PRESENT) && + !(flags & ACPI_STA_DEVICE_FUNCTIONING)) { + /* + * Don't examine the children of the device only when the + * device is neither present nor functional. See ACPI spec, + * description of _STA for more information. + */ return (AE_CTRL_DEPTH); } @@ -539,7 +542,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, * value is returned to the caller. * * This is a wrapper for walk_namespace, but the callback performs - * additional filtering. Please see acpi_get_device_callback. + * additional filtering. Please see acpi_ns_get_device_callback. * ******************************************************************************/ diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index b489781b22a8..a287ed550f54 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index faa375887201..2b375ee80cef 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a498a6cc68fe..235a1386888a 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -742,6 +742,7 @@ EXPORT_SYMBOL(acpi_os_execute); void acpi_os_wait_events_complete(void *context) { flush_workqueue(kacpid_wq); + flush_workqueue(kacpi_notify_wq); } EXPORT_SYMBOL(acpi_os_wait_events_complete); diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index c2b9835c890b..f1e8bf65e24e 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -230,12 +230,12 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, struct acpi_parse_state *parser_state, union acpi_parse_object *arg, u8 possible_method_call) { + acpi_status status; char *path; union acpi_parse_object *name_op; - acpi_status status; union acpi_operand_object *method_desc; struct acpi_namespace_node *node; - union acpi_generic_state scope_info; + u8 *start = parser_state->aml; ACPI_FUNCTION_TRACE(ps_get_next_namepath); @@ -249,25 +249,18 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_OK); } - /* Setup search scope info */ - - scope_info.scope.node = NULL; - node = parser_state->start_node; - if (node) { - scope_info.scope.node = node; - } - /* - * Lookup the name in the internal namespace. We don't want to add - * anything new to the namespace here, however, so we use MODE_EXECUTE. + * Lookup the name in the internal namespace, starting with the current + * scope. We don't want to add anything new to the namespace here, + * however, so we use MODE_EXECUTE. * Allow searching of the parent tree, but don't open a new scope - * we just want to lookup the object (must be mode EXECUTE to perform * the upsearch) */ - status = - acpi_ns_lookup(&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, - NULL, &node); + status = acpi_ns_lookup(walk_state->scope_info, path, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &node); /* * If this name is a control method invocation, we must @@ -275,6 +268,16 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { + if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) { + /* + * acpi_ps_get_next_namestring has increased the AML pointer, + * so we need to restore the saved AML pointer for method call. + */ + walk_state->parser_state.aml = start; + walk_state->arg_count = 1; + acpi_ps_init_op(arg, AML_INT_METHODCALL_OP); + return_ACPI_STATUS(AE_OK); + } /* This name is actually a control method invocation */ @@ -686,9 +689,29 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NO_MEMORY); } - status = - acpi_ps_get_next_namepath(walk_state, parser_state, - arg, 0); + /* To support super_name arg of Unload */ + + if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) { + status = + acpi_ps_get_next_namepath(walk_state, + parser_state, arg, + 1); + + /* + * If the super_name arg of Unload is a method call, + * we have restored the AML pointer, just free this Arg + */ + if (arg->common.aml_opcode == + AML_INT_METHODCALL_OP) { + acpi_ps_free_op(arg); + arg = NULL; + } + } else { + status = + acpi_ps_get_next_namepath(walk_state, + parser_state, arg, + 0); + } } else { /* Single complex argument, nothing returned */ diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index 773aee82fbb8..c06238e55d98 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -182,6 +182,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); unnamed_op->common.value.arg = NULL; + unnamed_op->common.arg_list_length = 0; unnamed_op->common.aml_opcode = walk_state->opcode; /* @@ -241,7 +242,8 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, acpi_ps_append_arg(*op, unnamed_op->common.value.arg); acpi_gbl_depth++; - if ((*op)->common.aml_opcode == AML_REGION_OP) { + if ((*op)->common.aml_opcode == AML_REGION_OP || + (*op)->common.aml_opcode == AML_DATA_REGION_OP) { /* * Defer final parsing of an operation_region body, because we don't * have enough info in the first pass to parse it correctly (i.e., @@ -280,6 +282,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, acpi_status status = AE_OK; union acpi_parse_object *op; union acpi_parse_object *named_op = NULL; + union acpi_parse_object *parent_scope; + u8 argument_count; + const struct acpi_opcode_info *op_info; ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); @@ -320,8 +325,32 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, op->named.length = 0; } - acpi_ps_append_arg(acpi_ps_get_parent_scope - (&(walk_state->parser_state)), op); + if (walk_state->opcode == AML_BANK_FIELD_OP) { + /* + * Backup to beginning of bank_field declaration + * body_length is unknown until we parse the body + */ + op->named.data = aml_op_start; + op->named.length = 0; + } + + parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state)); + acpi_ps_append_arg(parent_scope, op); + + if (parent_scope) { + op_info = + acpi_ps_get_opcode_info(parent_scope->common.aml_opcode); + if (op_info->flags & AML_HAS_TARGET) { + argument_count = + acpi_ps_get_argument_count(op_info->type); + if (parent_scope->common.arg_list_length > + argument_count) { + op->common.flags |= ACPI_PARSEOP_TARGET; + } + } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { + op->common.flags |= ACPI_PARSEOP_TARGET; + } + } if (walk_state->descending_callback != NULL) { /* @@ -603,13 +632,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, acpi_ps_pop_scope(&(walk_state->parser_state), op, &walk_state->arg_types, &walk_state->arg_count); - - if ((*op)->common.aml_opcode != AML_WHILE_OP) { - status2 = acpi_ds_result_stack_pop(walk_state); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - } } /* Close this iteration of the While loop */ @@ -640,10 +662,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, if (ACPI_FAILURE(status2)) { return_ACPI_STATUS(status2); } - status2 = acpi_ds_result_stack_pop(walk_state); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } acpi_ut_delete_generic_state (acpi_ut_pop_generic_state @@ -1005,7 +1023,8 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) acpi_gbl_depth--; } - if (op->common.aml_opcode == AML_REGION_OP) { + if (op->common.aml_opcode == AML_REGION_OP || + op->common.aml_opcode == AML_DATA_REGION_OP) { /* * Skip parsing of control method or opregion body, * because we don't have enough info in the first pass @@ -1030,6 +1049,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) (u32) (parser_state->aml - op->named.data); } + if (op->common.aml_opcode == AML_BANK_FIELD_OP) { + /* + * Backup to beginning of bank_field declaration + * + * body_length is unknown until we parse the body + */ + op->named.length = + (u32) (parser_state->aml - op->named.data); + } + /* This op complete, notify the dispatcher */ if (walk_state->ascending_callback != NULL) { diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 9296e86761d7..f425ab30eae8 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,9 @@ #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psopcode") +static const u8 acpi_gbl_argument_count[] = + { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 }; + /******************************************************************************* * * NAME: acpi_gbl_aml_op_info @@ -59,6 +62,7 @@ ACPI_MODULE_NAME("psopcode") * the operand type. * ******************************************************************************/ + /* * Summary of opcode types/flags * @@ -176,6 +180,7 @@ ACPI_MODULE_NAME("psopcode") AML_CREATE_QWORD_FIELD_OP ******************************************************************************/ + /* * Master Opcode information table. A summary of everything we know about each * opcode, all in one place. @@ -515,9 +520,10 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, - ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD | + AML_DEFER), /* Internal opcodes that map to invalid AML opcodes */ @@ -619,9 +625,9 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), /* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + AML_NSNODE | AML_NAMED | AML_DEFER), /* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, @@ -779,3 +785,25 @@ char *acpi_ps_get_opcode_name(u16 opcode) #endif } + +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_argument_count + * + * PARAMETERS: op_type - Type associated with the AML opcode + * + * RETURN: Argument count + * + * DESCRIPTION: Obtain the number of expected arguments for an AML opcode + * + ******************************************************************************/ + +u8 acpi_ps_get_argument_count(u32 op_type) +{ + + if (op_type <= AML_TYPE_EXEC_6A_0T_1R) { + return (acpi_gbl_argument_count[op_type]); + } + + return (0); +} diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index 5d63f48e56b5..15e1702e48d6 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -205,6 +205,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, || (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || (op->common.parent->common.aml_opcode == + AML_BANK_FIELD_OP) + || (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); @@ -349,19 +351,13 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, parser_state->aml = walk_state->aml_last_while; walk_state->control_state->common.value = FALSE; - status = acpi_ds_result_stack_pop(walk_state); - if (ACPI_SUCCESS(status)) { - status = AE_CTRL_BREAK; - } + status = AE_CTRL_BREAK; break; case AE_CTRL_CONTINUE: parser_state->aml = walk_state->aml_last_while; - status = acpi_ds_result_stack_pop(walk_state); - if (ACPI_SUCCESS(status)) { - status = AE_CTRL_CONTINUE; - } + status = AE_CTRL_CONTINUE; break; case AE_CTRL_PENDING: @@ -383,10 +379,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, * Just close out this package */ parser_state->aml = acpi_ps_get_next_package_end(parser_state); - status = acpi_ds_result_stack_pop(walk_state); - if (ACPI_SUCCESS(status)) { - status = AE_CTRL_PENDING; - } + status = AE_CTRL_PENDING; break; case AE_CTRL_FALSE: @@ -541,7 +534,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) if ((status == AE_ALREADY_EXISTS) && (!walk_state->method_desc->method.mutex)) { ACPI_INFO((AE_INFO, - "Marking method %4.4s as Serialized", + "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", walk_state->method_node->name. ascii)); @@ -601,6 +594,30 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) * The object is deleted */ if (!previous_walk_state->return_desc) { + /* + * In slack mode execution, if there is no return value + * we should implicitly return zero (0) as a default value. + */ + if (acpi_gbl_enable_interpreter_slack && + !previous_walk_state-> + implicit_return_obj) { + previous_walk_state-> + implicit_return_obj = + acpi_ut_create_internal_object + (ACPI_TYPE_INTEGER); + if (!previous_walk_state-> + implicit_return_obj) { + return_ACPI_STATUS + (AE_NO_MEMORY); + } + + previous_walk_state-> + implicit_return_obj-> + integer.value = 0; + } + + /* Restart the calling control method */ + status = acpi_ds_restart_control_method (walk_state, diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index 77cfa4ed0cfe..ee50e67c9443 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 966e7ea2a0c4..1dd355ddd182 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -171,6 +171,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) while (arg) { arg->common.parent = op; arg = arg->common.next; + + op->common.arg_list_length++; } } diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index 8ca52002db55..7cf1f65cd5bb 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index 49f9757434e4..8b86ad5a3201 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index 94103bced75e..52581454c47c 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 76bf6d90c700..81e4f081a4ae 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -93,6 +93,7 @@ struct acpi_power_resource { static struct list_head acpi_power_resource_list; static const struct file_operations acpi_power_fops = { + .owner = THIS_MODULE, .open = acpi_power_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -121,7 +122,7 @@ acpi_power_get_context(acpi_handle handle, } *resource = acpi_driver_data(device); - if (!resource) + if (!*resource) return -ENODEV; return 0; @@ -543,15 +544,11 @@ static int acpi_power_add_fs(struct acpi_device *device) } /* 'status' [R] */ - entry = create_proc_entry(ACPI_POWER_FILE_STATUS, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_POWER_FILE_STATUS, + S_IRUGO, acpi_device_dir(device), + &acpi_power_fops, acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_power_fops; - entry->data = acpi_driver_data(device); - } - return 0; } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a825b431b64f..386e5aa48834 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -112,6 +112,7 @@ static struct acpi_driver acpi_processor_driver = { #define UNINSTALL_NOTIFY_HANDLER 2 static const struct file_operations acpi_processor_info_fops = { + .owner = THIS_MODULE, .open = acpi_processor_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -326,40 +327,30 @@ static int acpi_processor_add_fs(struct acpi_device *device) acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_info_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'throttling' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_processor_throttling_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_throttling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'limit' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_processor_limit_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_limit_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -612,6 +603,15 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid) request_region(pr->throttling.address, 6, "ACPI CPU throttle"); } + /* + * If ACPI describes a slot number for this CPU, we can use it + * ensure we get the right value in the "physical id" field + * of /proc/cpuinfo + */ + status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); + if (ACPI_SUCCESS(status)) + arch_fix_phys_package_id(pr->id, object.integer.value); + return 0; } @@ -674,22 +674,21 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) result = PTR_ERR(pr->cdev); goto end; } - if (pr->cdev) { - printk(KERN_INFO PREFIX - "%s is registered as cooling_device%d\n", - device->dev.bus_id, pr->cdev->id); - - result = sysfs_create_link(&device->dev.kobj, - &pr->cdev->device.kobj, - "thermal_cooling"); - if (result) - return result; - result = sysfs_create_link(&pr->cdev->device.kobj, - &device->dev.kobj, - "device"); - if (result) - return result; - } + + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev.bus_id, pr->cdev->id); + + result = sysfs_create_link(&device->dev.kobj, + &pr->cdev->device.kobj, + "thermal_cooling"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + result = sysfs_create_link(&pr->cdev->device.kobj, + &device->dev.kobj, + "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); if (pr->flags.throttling) { printk(KERN_INFO PREFIX "%s [%s] (supports", diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0d90ff5fd117..2dd2c1f3a01c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -847,6 +847,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr) /* all processors need to support C1 */ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; pr->power.states[ACPI_STATE_C1].valid = 1; + pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT; } /* the C0 state only exists as a filler in our array */ pr->power.states[ACPI_STATE_C0].valid = 1; @@ -959,6 +960,9 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) cx.address); } + if (cx.type == ACPI_STATE_C1) { + cx.valid = 1; + } obj = &(element->package.elements[2]); if (obj->type != ACPI_TYPE_INTEGER) @@ -1282,6 +1286,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_processor_power_fops = { + .owner = THIS_MODULE, .open = acpi_processor_power_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -1294,6 +1299,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) { int result = 0; + if (boot_option_idle_override) + return 0; if (!pr) return -EINVAL; @@ -1733,6 +1740,9 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) { int ret; + if (boot_option_idle_override) + return 0; + if (!pr) return -EINVAL; @@ -1763,6 +1773,8 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct proc_dir_entry *entry = NULL; unsigned int i; + if (boot_option_idle_override) + return 0; if (!first_run) { dmi_check_system(processor_power_dmi_table); @@ -1798,7 +1810,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, * Note that we use previously set idle handler will be used on * platforms that only support C1. */ - if ((pr->flags.power) && (!boot_option_idle_override)) { + if (pr->flags.power) { #ifdef CONFIG_CPU_IDLE acpi_processor_setup_cpuidle(pr); pr->power.dev.cpu = pr->id; @@ -1822,24 +1834,23 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, } /* 'power' [R] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_power_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_power_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device) { + if (boot_option_idle_override) + return 0; + #ifdef CONFIG_CPU_IDLE - if ((pr->flags.power) && (!boot_option_idle_override)) + if (pr->flags.power) cpuidle_unregister_device(&pr->power.dev); #endif pr->flags.power_setup_done = 0; diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index b477a4be8a69..d80b2d1441af 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -411,6 +411,7 @@ EXPORT_SYMBOL(acpi_processor_notify_smm); static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_processor_perf_fops = { + .owner = THIS_MODULE, .open = acpi_processor_perf_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -456,7 +457,6 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) static void acpi_cpufreq_add_file(struct acpi_processor *pr) { - struct proc_dir_entry *entry = NULL; struct acpi_device *device = NULL; @@ -464,14 +464,9 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr) return; /* add file 'performance' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG | S_IRUGO, - acpi_device_dir(device)); - if (entry){ - entry->proc_fops = &acpi_processor_perf_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO, + acpi_device_dir(device), + &acpi_processor_perf_fops, acpi_driver_data(device)); return; } diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 9cb43f52f7b6..ef34b18f95ca 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -97,7 +97,7 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr) #define CPUFREQ_THERMAL_MIN_STEP 0 #define CPUFREQ_THERMAL_MAX_STEP 3 -static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; +static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); static unsigned int acpi_thermal_cpufreq_is_init = 0; static int cpu_has_cpufreq(unsigned int cpu) @@ -113,9 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return -ENODEV; - if (cpufreq_thermal_reduction_pctg[cpu] < + if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) < CPUFREQ_THERMAL_MAX_STEP) { - cpufreq_thermal_reduction_pctg[cpu]++; + per_cpu(cpufreq_thermal_reduction_pctg, cpu)++; cpufreq_update_policy(cpu); return 0; } @@ -128,14 +128,14 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return -ENODEV; - if (cpufreq_thermal_reduction_pctg[cpu] > + if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) > (CPUFREQ_THERMAL_MIN_STEP + 1)) - cpufreq_thermal_reduction_pctg[cpu]--; + per_cpu(cpufreq_thermal_reduction_pctg, cpu)--; else - cpufreq_thermal_reduction_pctg[cpu] = 0; + per_cpu(cpufreq_thermal_reduction_pctg, cpu) = 0; cpufreq_update_policy(cpu); /* We reached max freq again and can leave passive mode */ - return !cpufreq_thermal_reduction_pctg[cpu]; + return !per_cpu(cpufreq_thermal_reduction_pctg, cpu); } static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, @@ -147,9 +147,10 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, if (event != CPUFREQ_ADJUST) goto out; - max_freq = - (policy->cpuinfo.max_freq * - (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100; + max_freq = ( + policy->cpuinfo.max_freq * + (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20) + ) / 100; cpufreq_verify_within_limits(policy, 0, max_freq); @@ -174,7 +175,7 @@ static int cpufreq_get_cur_state(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return 0; - return cpufreq_thermal_reduction_pctg[cpu]; + return per_cpu(cpufreq_thermal_reduction_pctg, cpu); } static int cpufreq_set_cur_state(unsigned int cpu, int state) @@ -182,7 +183,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) if (!cpu_has_cpufreq(cpu)) return 0; - cpufreq_thermal_reduction_pctg[cpu] = state; + per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state; cpufreq_update_policy(cpu); return 0; } @@ -191,8 +192,9 @@ void acpi_thermal_cpufreq_init(void) { int i; - for (i = 0; i < NR_CPUS; i++) - cpufreq_thermal_reduction_pctg[i] = 0; + for (i = 0; i < nr_cpu_ids; i++) + if (cpu_present(i)) + per_cpu(cpufreq_thermal_reduction_pctg, i) = 0; i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); @@ -507,6 +509,7 @@ static ssize_t acpi_processor_write_limit(struct file * file, } struct file_operations acpi_processor_limit_fops = { + .owner = THIS_MODULE, .open = acpi_processor_limit_open_fs, .read = seq_read, .write = acpi_processor_write_limit, diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 0bba3a914e86..bb06738860c4 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1252,6 +1252,7 @@ static ssize_t acpi_processor_write_throttling(struct file *file, } struct file_operations acpi_processor_throttling_fops = { + .owner = THIS_MODULE, .open = acpi_processor_throttling_open_fs, .read = seq_read, .write = acpi_processor_write_throttling, diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c index 271e61509eeb..7f96332822bf 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/resources/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 0dd2ce8a3475..8a112d11d491 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,7 +73,7 @@ acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length); static u8 acpi_rs_count_set_bits(u16 bit_field) { - u8 bits_set; + acpi_native_uint bits_set; ACPI_FUNCTION_ENTRY(); @@ -81,10 +81,10 @@ static u8 acpi_rs_count_set_bits(u16 bit_field) /* Zero the least significant bit that is set */ - bit_field &= (bit_field - 1); + bit_field &= (u16) (bit_field - 1); } - return (bits_set); + return ((u8) bits_set); } /******************************************************************************* @@ -211,6 +211,24 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) * variable-length fields */ switch (resource->type) { + case ACPI_RESOURCE_TYPE_IRQ: + + /* Length can be 3 or 2 */ + + if (resource->data.irq.descriptor_length == 2) { + total_size--; + } + break; + + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + + /* Length can be 1 or 0 */ + + if (resource->data.irq.descriptor_length == 0) { + total_size--; + } + break; + case ACPI_RESOURCE_TYPE_VENDOR: /* * Vendor Defined Resource: diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 50da494c3ee2..faddaee1bc07 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index 46da116a4030..6bbbb7b8941a 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -87,8 +87,10 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table); * ******************************************************************************/ -struct acpi_rsdump_info acpi_rs_dump_irq[6] = { +struct acpi_rsdump_info acpi_rs_dump_irq[7] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length), + "Descriptor Length", NULL}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering", acpi_gbl_he_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity", @@ -115,9 +117,11 @@ struct acpi_rsdump_info acpi_rs_dump_dma[6] = { NULL} }; -struct acpi_rsdump_info acpi_rs_dump_start_dpf[3] = { +struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf), "Start-Dependent-Functions", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length), + "Descriptor Length", NULL}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority), "Compatibility Priority", acpi_gbl_config_decode}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness), diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c index 2c2adb6292c1..3f0a1fedbe0e 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/resources/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c index b297bc3e4419..b66d42e7402e 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/resources/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -185,7 +185,7 @@ struct acpi_rsconvert_info acpi_rs_convert_end_tag[2] = { * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = { +struct acpi_rsconvert_info acpi_rs_get_start_dpf[6] = { {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT, ACPI_RS_SIZE(struct acpi_resource_start_dependent), ACPI_RSC_TABLE_SIZE(acpi_rs_get_start_dpf)}, @@ -196,6 +196,12 @@ struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = { ACPI_ACCEPTABLE_CONFIGURATION, 2}, + /* Get the descriptor length (0 or 1 for Start Dpf descriptor) */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.start_dpf.descriptor_length), + AML_OFFSET(start_dpf.descriptor_type), + 0}, + /* All done if there is no flag byte present in the descriptor */ {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1}, @@ -219,7 +225,9 @@ struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = { * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = { +struct acpi_rsconvert_info acpi_rs_set_start_dpf[10] = { + /* Start with a default descriptor of length 1 */ + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT, sizeof(struct aml_resource_start_dependent), ACPI_RSC_TABLE_SIZE(acpi_rs_set_start_dpf)}, @@ -236,6 +244,33 @@ struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = { AML_OFFSET(start_dpf.flags), 2}, /* + * All done if the output descriptor length is required to be 1 + * (i.e., optimization to 0 bytes cannot be attempted) + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.start_dpf.descriptor_length), + 1}, + + /* Set length to 0 bytes (no flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, + sizeof(struct aml_resource_start_dependent_noprio)}, + + /* + * All done if the output descriptor length is required to be 0. + * + * TBD: Perhaps we should check for error if input flags are not + * compatible with a 0-byte descriptor. + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.start_dpf.descriptor_length), + 0}, + + /* Reset length to 1 byte (descriptor with flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_start_dependent)}, + + /* * All done if flags byte is necessary -- if either priority value * is not ACPI_ACCEPTABLE_CONFIGURATION */ diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c index 5657f7b95039..a8805efc0366 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/resources/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,7 @@ ACPI_MODULE_NAME("rsirq") * acpi_rs_get_irq * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_get_irq[7] = { +struct acpi_rsconvert_info acpi_rs_get_irq[8] = { {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ, ACPI_RS_SIZE(struct acpi_resource_irq), ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)}, @@ -69,6 +69,12 @@ struct acpi_rsconvert_info acpi_rs_get_irq[7] = { ACPI_EDGE_SENSITIVE, 1}, + /* Get the descriptor length (2 or 3 for IRQ descriptor) */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.irq.descriptor_length), + AML_OFFSET(irq.descriptor_type), + 0}, + /* All done if no flag byte present in descriptor */ {ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3}, @@ -94,7 +100,9 @@ struct acpi_rsconvert_info acpi_rs_get_irq[7] = { * ******************************************************************************/ -struct acpi_rsconvert_info acpi_rs_set_irq[9] = { +struct acpi_rsconvert_info acpi_rs_set_irq[13] = { + /* Start with a default descriptor of length 3 */ + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ, sizeof(struct aml_resource_irq), ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)}, @@ -105,7 +113,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = { AML_OFFSET(irq.irq_mask), ACPI_RS_OFFSET(data.irq.interrupt_count)}, - /* Set the flags byte by default */ + /* Set the flags byte */ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering), AML_OFFSET(irq.flags), @@ -118,6 +126,33 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = { {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable), AML_OFFSET(irq.flags), 4}, + + /* + * All done if the output descriptor length is required to be 3 + * (i.e., optimization to 2 bytes cannot be attempted) + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.irq.descriptor_length), + 3}, + + /* Set length to 2 bytes (no flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)}, + + /* + * All done if the output descriptor length is required to be 2. + * + * TBD: Perhaps we should check for error if input flags are not + * compatible with a 2-byte descriptor. + */ + {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE, + ACPI_RS_OFFSET(data.irq.descriptor_length), + 2}, + + /* Reset length to 3 bytes (descriptor with flags byte) */ + + {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)}, + /* * Check if the flags byte is necessary. Not needed if the flags are: * ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE @@ -134,7 +169,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = { ACPI_RS_OFFSET(data.irq.sharable), ACPI_EXCLUSIVE}, - /* irq_no_flags() descriptor can be used */ + /* We can optimize to a 2-byte irq_no_flags() descriptor */ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)} }; diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index ca21e4660c79..b78c7e797a19 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c index 521eab7dd8df..63b21abd90bb 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/resources/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index c7081afa893a..de1ac3881b22 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -497,6 +497,17 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, } break; + case ACPI_RSC_EXIT_EQ: + /* + * Control - Exit conversion if equal + */ + if (*ACPI_ADD_PTR(u8, resource, + COMPARE_TARGET(info)) == + COMPARE_VALUE(info)) { + goto exit; + } + break; + default: ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index 11c0bd7b9cfd..befe2302f41b 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -97,17 +97,17 @@ u8 acpi_rs_decode_bitmask(u16 mask, u8 * list) u16 acpi_rs_encode_bitmask(u8 * list, u8 count) { acpi_native_uint i; - u16 mask; + acpi_native_uint mask; ACPI_FUNCTION_ENTRY(); /* Encode the list into a single bitmask */ for (i = 0, mask = 0; i < count; i++) { - mask |= (0x0001 << list[i]); + mask |= (0x1 << list[i]); } - return (mask); + return ((u16) mask); } /******************************************************************************* diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 4c3fd4cdaf73..f59f4c4e034c 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 585ae3c9c8ea..10a36512647c 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -483,8 +483,6 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, struct file_operations *state_fops, struct file_operations *alarm_fops, void *data) { - struct proc_dir_entry *entry = NULL; - if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { @@ -494,34 +492,19 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, } /* 'info' [R] */ - if (info_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = info_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (info_fops) + proc_create_data(ACPI_SBS_FILE_INFO, S_IRUGO, *dir, + info_fops, data); /* 'state' [R] */ - if (state_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = state_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (state_fops) + proc_create_data(ACPI_SBS_FILE_STATE, S_IRUGO, *dir, + state_fops, data); /* 'alarm' [R/W] */ - if (alarm_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = alarm_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (alarm_fops) + proc_create_data(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir, + alarm_fops, data); return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e6ce262b5d44..6d85289f1c12 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -677,9 +677,8 @@ acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, device->wakeup.resources.count = package->package.count - 2; for (i = 0; i < device->wakeup.resources.count; i++) { element = &(package->package.elements[i + 2]); - if (element->type != ACPI_TYPE_ANY) { + if (element->type != ACPI_TYPE_LOCAL_REFERENCE) return AE_BAD_DATA; - } device->wakeup.resources.handles[i] = element->reference.handle; } @@ -692,6 +691,9 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *package = NULL; + union acpi_object in_arg[3]; + struct acpi_object_list arg_list = { 3, in_arg }; + acpi_status psw_status = AE_OK; struct acpi_device_id button_device_ids[] = { {"PNP0C0D", 0}, @@ -700,7 +702,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) {"", 0}, }; - /* _PRW */ status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); if (ACPI_FAILURE(status)) { @@ -718,6 +719,45 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) kfree(buffer.pointer); device->wakeup.flags.valid = 1; + /* Call _PSW/_DSW object to disable its ability to wake the sleeping + * system for the ACPI device with the _PRW object. + * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. + * So it is necessary to call _DSW object first. Only when it is not + * present will the _PSW object used. + */ + /* + * Three agruments are needed for the _DSW object. + * Argument 0: enable/disable the wake capabilities + * When _DSW object is called to disable the wake capabilities, maybe + * the first argument is filled. The value of the other two agruments + * is meaningless. + */ + in_arg[0].type = ACPI_TYPE_INTEGER; + in_arg[0].integer.value = 0; + in_arg[1].type = ACPI_TYPE_INTEGER; + in_arg[1].integer.value = 0; + in_arg[2].type = ACPI_TYPE_INTEGER; + in_arg[2].integer.value = 0; + psw_status = acpi_evaluate_object(device->handle, "_DSW", + &arg_list, NULL); + if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n")); + /* + * When the _DSW object is not present, OSPM will call _PSW object. + */ + if (psw_status == AE_NOT_FOUND) { + /* + * Only one agruments is required for the _PSW object. + * agrument 0: enable/disable the wake capabilities + */ + arg_list.count = 1; + in_arg[0].integer.value = 0; + psw_status = acpi_evaluate_object(device->handle, "_PSW", + &arg_list, NULL); + if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in " + "evaluate _PSW\n")); + } /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) device->wakeup.flags.run_wake = 1; @@ -882,10 +922,7 @@ static void acpi_device_get_busid(struct acpi_device *device, static int acpi_video_bus_match(struct acpi_device *device) { - acpi_handle h_dummy1; - acpi_handle h_dummy2; - acpi_handle h_dummy3; - + acpi_handle h_dummy; if (!device) return -EINVAL; @@ -895,18 +932,18 @@ acpi_video_bus_match(struct acpi_device *device) */ /* Does this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) return 0; /* Does this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) return 0; /* Does this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) return 0; return -ENODEV; diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 71183eea7906..c3b0cd88d09f 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -51,7 +51,7 @@ static int acpi_sleep_prepare(u32 acpi_state) } #ifdef CONFIG_SUSPEND -static struct platform_suspend_ops acpi_pm_ops; +static struct platform_suspend_ops acpi_suspend_ops; extern void do_suspend_lowlevel(void); @@ -65,11 +65,11 @@ static u32 acpi_suspend_states[] = { static int init_8259A_after_S1; /** - * acpi_pm_begin - Set the target system sleep state to the state + * acpi_suspend_begin - Set the target system sleep state to the state * associated with given @pm_state, if supported. */ -static int acpi_pm_begin(suspend_state_t pm_state) +static int acpi_suspend_begin(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; @@ -85,13 +85,13 @@ static int acpi_pm_begin(suspend_state_t pm_state) } /** - * acpi_pm_prepare - Do preliminary suspend work. + * acpi_suspend_prepare - Do preliminary suspend work. * * If necessary, set the firmware waking vector and do arch-specific * nastiness to get the wakeup code to the waking vector. */ -static int acpi_pm_prepare(void) +static int acpi_suspend_prepare(void) { int error = acpi_sleep_prepare(acpi_target_sleep_state); @@ -104,7 +104,7 @@ static int acpi_pm_prepare(void) } /** - * acpi_pm_enter - Actually enter a sleep state. + * acpi_suspend_enter - Actually enter a sleep state. * @pm_state: ignored * * Flush caches and go to sleep. For STR we have to call arch-specific @@ -112,7 +112,7 @@ static int acpi_pm_prepare(void) * It's unfortunate, but it works. Please fix if you're feeling frisky. */ -static int acpi_pm_enter(suspend_state_t pm_state) +static int acpi_suspend_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; @@ -169,13 +169,13 @@ static int acpi_pm_enter(suspend_state_t pm_state) } /** - * acpi_pm_finish - Instruct the platform to leave a sleep state. + * acpi_suspend_finish - Instruct the platform to leave a sleep state. * * This is called after we wake back up (or if entering the sleep state * failed). */ -static void acpi_pm_finish(void) +static void acpi_suspend_finish(void) { u32 acpi_state = acpi_target_sleep_state; @@ -196,19 +196,19 @@ static void acpi_pm_finish(void) } /** - * acpi_pm_end - Finish up suspend sequence. + * acpi_suspend_end - Finish up suspend sequence. */ -static void acpi_pm_end(void) +static void acpi_suspend_end(void) { /* - * This is necessary in case acpi_pm_finish() is not called during a + * This is necessary in case acpi_suspend_finish() is not called during a * failing transition to a sleep state. */ acpi_target_sleep_state = ACPI_STATE_S0; } -static int acpi_pm_state_valid(suspend_state_t pm_state) +static int acpi_suspend_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -224,13 +224,13 @@ static int acpi_pm_state_valid(suspend_state_t pm_state) } } -static struct platform_suspend_ops acpi_pm_ops = { - .valid = acpi_pm_state_valid, - .begin = acpi_pm_begin, - .prepare = acpi_pm_prepare, - .enter = acpi_pm_enter, - .finish = acpi_pm_finish, - .end = acpi_pm_end, +static struct platform_suspend_ops acpi_suspend_ops = { + .valid = acpi_suspend_state_valid, + .begin = acpi_suspend_begin, + .prepare = acpi_suspend_prepare, + .enter = acpi_suspend_enter, + .finish = acpi_suspend_finish, + .end = acpi_suspend_end, }; /* @@ -492,7 +492,7 @@ int __init acpi_sleep_init(void) } } - suspend_set_ops(&acpi_pm_ops); + suspend_set_ops(&acpi_suspend_ops); #endif #ifdef CONFIG_HIBERNATION diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index f8df5217d477..8a5fe8710513 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -440,6 +440,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_system_wakeup_device_fops = { + .owner = THIS_MODULE, .open = acpi_system_wakeup_device_open_fs, .read = seq_read, .write = acpi_system_write_wakeup_device, @@ -449,6 +450,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = { #ifdef CONFIG_ACPI_PROCFS static const struct file_operations acpi_system_sleep_fops = { + .owner = THIS_MODULE, .open = acpi_system_sleep_open_fs, .read = seq_read, .write = acpi_system_write_sleep, @@ -459,6 +461,7 @@ static const struct file_operations acpi_system_sleep_fops = { #ifdef HAVE_ACPI_LEGACY_ALARM static const struct file_operations acpi_system_alarm_fops = { + .owner = THIS_MODULE, .open = acpi_system_alarm_open_fs, .read = seq_read, .write = acpi_system_write_alarm, @@ -477,37 +480,26 @@ static u32 rtc_handler(void *context) static int __init acpi_sleep_proc_init(void) { - struct proc_dir_entry *entry = NULL; - if (acpi_disabled) return 0; #ifdef CONFIG_ACPI_PROCFS /* 'sleep' [R/W] */ - entry = - create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_sleep_fops; + proc_create("sleep", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_sleep_fops); #endif /* CONFIG_ACPI_PROCFS */ #ifdef HAVE_ACPI_LEGACY_ALARM /* 'alarm' [R/W] */ - entry = - create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_alarm_fops; + proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_alarm_fops); acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); #endif /* HAVE_ACPI_LEGACY_ALARM */ /* 'wakeup device' [R/W] */ - entry = - create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_wakeup_device_fops; + proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_wakeup_device_fops); return 0; } diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 4749f379a915..769f24855eb6 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -396,6 +396,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_system_info_ops = { + .owner = THIS_MODULE, .open = acpi_system_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -406,6 +407,7 @@ static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); static const struct file_operations acpi_system_dsdt_ops = { + .owner = THIS_MODULE, .read = acpi_system_read_dsdt, }; @@ -430,6 +432,7 @@ static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t, loff_t *); static const struct file_operations acpi_system_fadt_ops = { + .owner = THIS_MODULE, .read = acpi_system_read_fadt, }; @@ -454,31 +457,23 @@ static int acpi_system_procfs_init(void) { struct proc_dir_entry *entry; int error = 0; - char *name; /* 'info' [R] */ - name = ACPI_SYSTEM_FILE_INFO; - entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); + entry = proc_create(ACPI_SYSTEM_FILE_INFO, S_IRUGO, acpi_root_dir, + &acpi_system_info_ops); if (!entry) goto Error; - else { - entry->proc_fops = &acpi_system_info_ops; - } /* 'dsdt' [R] */ - name = ACPI_SYSTEM_FILE_DSDT; - entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_dsdt_ops; - else + entry = proc_create(ACPI_SYSTEM_FILE_DSDT, S_IRUSR, acpi_root_dir, + &acpi_system_dsdt_ops); + if (!entry) goto Error; /* 'fadt' [R] */ - name = ACPI_SYSTEM_FILE_FADT; - entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_fadt_ops; - else + entry = proc_create(ACPI_SYSTEM_FILE_FADT, S_IRUSR, acpi_root_dir, + &acpi_system_fadt_ops); + if (!entry) goto Error; Done: diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index 002bb33003af..949d4114eb9f 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c index 058c064948e1..9ca3afc98c80 100644 --- a/drivers/acpi/tables/tbfind.c +++ b/drivers/acpi/tables/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,12 +70,22 @@ acpi_tb_find_table(char *signature, { acpi_native_uint i; acpi_status status; + struct acpi_table_header header; ACPI_FUNCTION_TRACE(tb_find_table); + /* Normalize the input strings */ + + ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header)); + ACPI_STRNCPY(header.signature, signature, ACPI_NAME_SIZE); + ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); + ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); + + /* Search for the table */ + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature), - signature, ACPI_NAME_SIZE)) { + header.signature, ACPI_NAME_SIZE)) { /* Not the requested table */ @@ -104,20 +114,24 @@ acpi_tb_find_table(char *signature, if (!ACPI_MEMCMP (acpi_gbl_root_table_list.tables[i].pointer->signature, - signature, ACPI_NAME_SIZE) && (!oem_id[0] - || - !ACPI_MEMCMP - (acpi_gbl_root_table_list. - tables[i].pointer->oem_id, - oem_id, ACPI_OEM_ID_SIZE)) + header.signature, ACPI_NAME_SIZE) && (!oem_id[0] + || + !ACPI_MEMCMP + (acpi_gbl_root_table_list. + tables[i].pointer-> + oem_id, + header.oem_id, + ACPI_OEM_ID_SIZE)) && (!oem_table_id[0] || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i]. - pointer->oem_table_id, oem_table_id, + pointer->oem_table_id, + header.oem_table_id, ACPI_OEM_TABLE_ID_SIZE))) { *table_index = i; ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Found table [%4.4s]\n", signature)); + "Found table [%4.4s]\n", + header.signature)); return_ACPI_STATUS(AE_OK); } } diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 3bc0c67a9283..402f93e1ff20 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -125,13 +125,20 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, /* The table must be either an SSDT or a PSDT or an OEMx */ - if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)) - && - (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) - && (strncmp(table_desc->pointer->signature, "OEM", 3))) { - ACPI_ERROR((AE_INFO, - "Table has invalid signature [%4.4s], must be SSDT, PSDT or OEMx", - table_desc->pointer->signature)); + if (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)&& + !ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)&& + strncmp(table_desc->pointer->signature, "OEM", 3)) { + /* Check for a printable name */ + if (acpi_ut_valid_acpi_name( + *(u32 *) table_desc->pointer->signature)) { + ACPI_ERROR((AE_INFO, "Table has invalid signature " + "[%4.4s], must be SSDT or PSDT", + table_desc->pointer->signature)); + } else { + ACPI_ERROR((AE_INFO, "Table has invalid signature " + "(0x%8.8X), must be SSDT or PSDT", + *(u32 *) table_desc->pointer->signature)); + } return_ACPI_STATUS(AE_BAD_SIGNATURE); } @@ -162,6 +169,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, acpi_tb_delete_table(table_desc); *table_index = i; + status = AE_ALREADY_EXISTS; goto release; } diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 010f19652f80..bc019b9b6a68 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -212,7 +212,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length) if (checksum) { ACPI_WARNING((AE_INFO, - "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X", + "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X", table->signature, table->checksum, (u8) (table->checksum - checksum))); diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index a9e3331fee5d..fb57b93c2495 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -635,6 +635,95 @@ acpi_status acpi_load_tables(void) ACPI_EXPORT_SYMBOL(acpi_load_tables) +/******************************************************************************* + * + * FUNCTION: acpi_install_table_handler + * + * PARAMETERS: Handler - Table event handler + * Context - Value passed to the handler on each event + * + * RETURN: Status + * + * DESCRIPTION: Install table event handler + * + ******************************************************************************/ +acpi_status +acpi_install_table_handler(acpi_tbl_handler handler, void *context) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_install_table_handler); + + if (!handler) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Don't allow more than one handler */ + + if (acpi_gbl_table_handler) { + status = AE_ALREADY_EXISTS; + goto cleanup; + } + + /* Install the handler */ + + acpi_gbl_table_handler = handler; + acpi_gbl_table_handler_context = context; + + cleanup: + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_install_table_handler) + +/******************************************************************************* + * + * FUNCTION: acpi_remove_table_handler + * + * PARAMETERS: Handler - Table event handler that was installed + * previously. + * + * RETURN: Status + * + * DESCRIPTION: Remove table event handler + * + ******************************************************************************/ +acpi_status acpi_remove_table_handler(acpi_tbl_handler handler) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_remove_table_handler); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Make sure that the installed handler is the same */ + + if (!handler || handler != acpi_gbl_table_handler) { + status = AE_BAD_PARAMETER; + goto cleanup; + } + + /* Remove the handler */ + + acpi_gbl_table_handler = NULL; + + cleanup: + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_remove_table_handler) + + static int __init acpi_no_auto_ssdt_setup(char *s) { printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n"); diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 9ecb4b6c1e7d..b8c0dfa084f6 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 1bcecc7dd2ca..504385b1f211 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -198,6 +198,7 @@ struct acpi_thermal { }; static const struct file_operations acpi_thermal_state_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -205,6 +206,7 @@ static const struct file_operations acpi_thermal_state_fops = { }; static const struct file_operations acpi_thermal_temp_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_temp_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -212,6 +214,7 @@ static const struct file_operations acpi_thermal_temp_fops = { }; static const struct file_operations acpi_thermal_trip_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_trip_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -219,6 +222,7 @@ static const struct file_operations acpi_thermal_trip_fops = { }; static const struct file_operations acpi_thermal_cooling_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_cooling_open_fs, .read = seq_read, .write = acpi_thermal_write_cooling_mode, @@ -227,6 +231,7 @@ static const struct file_operations acpi_thermal_cooling_fops = { }; static const struct file_operations acpi_thermal_polling_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_polling_open_fs, .read = seq_read, .write = acpi_thermal_write_polling, @@ -884,10 +889,15 @@ static void acpi_thermal_check(void *data) static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) { struct acpi_thermal *tz = thermal->devdata; + int result; if (!tz) return -EINVAL; + result = acpi_thermal_get_temperature(tz); + if (result) + return result; + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature)); } @@ -1012,6 +1022,18 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, return -EINVAL; } +static int thermal_get_crit_temp(struct thermal_zone_device *thermal, + unsigned long *temperature) { + struct acpi_thermal *tz = thermal->devdata; + + if (tz->trips.critical.flags.valid) { + *temperature = KELVIN_TO_MILLICELSIUS( + tz->trips.critical.temperature); + return 0; + } else + return -EINVAL; +} + typedef int (*cb)(struct thermal_zone_device *, int, struct thermal_cooling_device *); static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, @@ -1103,6 +1125,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .set_mode = thermal_set_mode, .get_trip_type = thermal_get_trip_type, .get_trip_temp = thermal_get_trip_temp, + .get_crit_temp = thermal_get_crit_temp, }; static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) @@ -1123,7 +1146,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].flags.valid; i++, trips++); - tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone", + tz->thermal_zone = thermal_zone_device_register("acpitz", trips, tz, &acpi_thermal_zone_ops); if (IS_ERR(tz->thermal_zone)) return -ENODEV; @@ -1419,63 +1442,47 @@ static int acpi_thermal_add_fs(struct acpi_device *device) } /* 'state' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_thermal_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'temperature' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE, + S_IRUGO, acpi_device_dir(device), + &acpi_thermal_temp_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_temp_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'trip_points' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, - S_IRUGO, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS, + S_IRUGO, + acpi_device_dir(device), + &acpi_thermal_trip_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_trip_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'cooling_mode' [R/W] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_thermal_cooling_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_cooling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'polling_frequency' [R/W] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_thermal_polling_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_polling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -1710,7 +1717,6 @@ static int acpi_thermal_resume(struct acpi_device *device) return AE_OK; } -#ifdef CONFIG_DMI static int thermal_act(const struct dmi_system_id *d) { if (act == 0) { @@ -1785,7 +1791,6 @@ static struct dmi_system_id thermal_dmi_table[] __initdata = { }, {} }; -#endif /* CONFIG_DMI */ static int __init acpi_thermal_init(void) { diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 6e56d5f7c43a..ede084829a70 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -147,7 +147,7 @@ acpi_status acpi_ut_delete_caches(void) if (acpi_gbl_display_final_mem_stats) { ACPI_STRCPY(buffer, "MEMORY"); - acpi_db_display_statistics(buffer); + (void)acpi_db_display_statistics(buffer); } #endif diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 285a0f531760..245fa80cf600 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 879eaa10d3ae..655c290aca7b 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,8 @@ #include <acpi/acpi.h> #include <acpi/amlcode.h> +#include <acpi/acnamesp.h> + #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utcopy") @@ -172,22 +174,21 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, case ACPI_TYPE_LOCAL_REFERENCE: - /* - * This is an object reference. Attempt to dereference it. - */ + /* This is an object reference. */ + switch (internal_object->reference.opcode) { case AML_INT_NAMEPATH_OP: /* For namepath, return the object handle ("reference") */ default: - /* - * Use the object type of "Any" to indicate a reference - * to object containing a handle to an ACPI named object. - */ - external_object->type = ACPI_TYPE_ANY; + + /* We are referring to the namespace node */ + external_object->reference.handle = internal_object->reference.node; + external_object->reference.actual_type = + acpi_ns_get_type(internal_object->reference.node); break; } break; @@ -215,6 +216,11 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, /* * There is no corresponding external object type */ + ACPI_ERROR((AE_INFO, + "Unsupported object type, cannot convert to external object: %s", + acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE + (internal_object)))); + return_ACPI_STATUS(AE_SUPPORT); } @@ -455,6 +461,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: case ACPI_TYPE_INTEGER: + case ACPI_TYPE_LOCAL_REFERENCE: internal_object = acpi_ut_create_internal_object((u8) external_object-> @@ -464,9 +471,18 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, } break; + case ACPI_TYPE_ANY: /* This is the case for a NULL object */ + + *ret_internal_object = NULL; + return_ACPI_STATUS(AE_OK); + default: /* All other types are not supported */ + ACPI_ERROR((AE_INFO, + "Unsupported object type, cannot convert to internal object: %s", + acpi_ut_get_type_name(external_object->type))); + return_ACPI_STATUS(AE_SUPPORT); } @@ -502,6 +518,10 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, external_object->buffer.length); internal_object->buffer.length = external_object->buffer.length; + + /* Mark buffer data valid */ + + internal_object->buffer.flags |= AOPOBJ_DATA_VALID; break; case ACPI_TYPE_INTEGER: @@ -509,6 +529,15 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, internal_object->integer.value = external_object->integer.value; break; + case ACPI_TYPE_LOCAL_REFERENCE: + + /* TBD: should validate incoming handle */ + + internal_object->reference.opcode = AML_INT_NAMEPATH_OP; + internal_object->reference.node = + external_object->reference.handle; + break; + default: /* Other types can't get here */ break; @@ -570,13 +599,17 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, /* Truncate package and delete it */ - package_object->package.count = i; + package_object->package.count = (u32) i; package_elements[i] = NULL; acpi_ut_remove_reference(package_object); return_ACPI_STATUS(status); } } + /* Mark package data valid */ + + package_object->package.flags |= AOPOBJ_DATA_VALID; + *internal_object = package_object; return_ACPI_STATUS(status); } @@ -709,7 +742,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, /* * We copied the reference object, so we now must add a reference * to the object pointed to by the reference + * + * DDBHandle reference (from Load/load_table is a special reference, + * it's Reference.Object is the table index, so does not need to + * increase the reference count */ + if (source_desc->reference.opcode == AML_LOAD_OP) { + break; + } + acpi_ut_add_reference(source_desc->reference.object); break; diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 7361204b1eef..f938f465efa4 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,9 +68,9 @@ static const char *acpi_ut_trim_function_name(const char *function_name); void acpi_ut_init_stack_ptr_trace(void) { - u32 current_sp; + acpi_size current_sp; - acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF(¤t_sp, NULL); + acpi_gbl_entry_stack_pointer = ¤t_sp; } /******************************************************************************* @@ -89,10 +89,8 @@ void acpi_ut_track_stack_ptr(void) { acpi_size current_sp; - current_sp = ACPI_PTR_DIFF(¤t_sp, NULL); - - if (current_sp < acpi_gbl_lowest_stack_pointer) { - acpi_gbl_lowest_stack_pointer = current_sp; + if (¤t_sp < acpi_gbl_lowest_stack_pointer) { + acpi_gbl_lowest_stack_pointer = ¤t_sp; } if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) { @@ -203,6 +201,7 @@ acpi_ut_debug_print(u32 requested_debug_level, va_start(args, format); acpi_os_vprintf(format, args); + va_end(args); } ACPI_EXPORT_SYMBOL(acpi_ut_debug_print) @@ -240,6 +239,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level, va_start(args, format); acpi_os_vprintf(format, args); + va_end(args); } ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw) @@ -524,6 +524,11 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) u32 temp32; u8 buf_char; + if (!buffer) { + acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n"); + return; + } + if ((count < 4) || (count & 0x01)) { display = DB_BYTE_DISPLAY; } diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index f777cebdc46d..1fbc35139e84 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -158,7 +158,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) "***** Mutex %p, OS Mutex %p\n", object, object->mutex.os_mutex)); - if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + if (object == acpi_gbl_global_lock_mutex) { /* Global Lock has extra semaphore */ @@ -252,6 +252,17 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) } break; + case ACPI_TYPE_LOCAL_BANK_FIELD: + + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, + "***** Bank Field %p\n", object)); + + second_desc = acpi_ns_get_secondary_object(object); + if (second_desc) { + acpi_ut_delete_object_desc(second_desc); + } + break; + default: break; } @@ -524,10 +535,12 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) case ACPI_TYPE_LOCAL_REFERENCE: /* - * The target of an Index (a package, string, or buffer) must track - * changes to the ref count of the index. + * The target of an Index (a package, string, or buffer) or a named + * reference must track changes to the ref count of the index or + * target object. */ - if (object->reference.opcode == AML_INDEX_OP) { + if ((object->reference.opcode == AML_INDEX_OP) || + (object->reference.opcode == AML_INT_NAMEPATH_OP)) { next_object = object->reference.object; } break; diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 0042b7e78b26..05e61be267d5 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 630c9a2c5b7b..a6e71b801d2d 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -602,6 +602,48 @@ char *acpi_ut_get_mutex_name(u32 mutex_id) return (acpi_gbl_mutex_names[mutex_id]); } + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_notify_name + * + * PARAMETERS: notify_value - Value from the Notify() request + * + * RETURN: String corresponding to the Notify Value. + * + * DESCRIPTION: Translate a Notify Value to a notify namestring. + * + ******************************************************************************/ + +/* Names for Notify() values, used for debug output */ + +static const char *acpi_gbl_notify_value_names[] = { + "Bus Check", + "Device Check", + "Device Wake", + "Eject Request", + "Device Check Light", + "Frequency Mismatch", + "Bus Mode Mismatch", + "Power Fault", + "Capabilities Check", + "Device PLD Check", + "Reserved", + "System Locality Update" +}; + +const char *acpi_ut_get_notify_name(u32 notify_value) +{ + + if (notify_value <= ACPI_NOTIFY_MAX) { + return (acpi_gbl_notify_value_names[notify_value]); + } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) { + return ("Reserved"); + } else { /* Greater or equal to 0x80 */ + + return ("**Device Specific**"); + } +} #endif /******************************************************************************* @@ -675,12 +717,13 @@ void acpi_ut_init_globals(void) acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL; - /* Global notify handlers */ + /* Global handlers */ acpi_gbl_system_notify.handler = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_exception_handler = NULL; acpi_gbl_init_handler = NULL; + acpi_gbl_table_handler = NULL; /* Global Lock support */ @@ -722,7 +765,7 @@ void acpi_ut_init_globals(void) acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST; #ifdef ACPI_DEBUG_OUTPUT - acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX; + acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX); #endif #ifdef ACPI_DBG_TRACK_ALLOCATIONS diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index ad3c0d0a5cf8..cae515fc02d3 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -125,9 +125,12 @@ void acpi_ut_subsystem_shutdown(void) acpi_gbl_startup_flags = 0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); +#ifndef ACPI_ASL_COMPILER + /* Close the acpi_event Handling */ acpi_ev_terminate(); +#endif /* Close the Namespace */ diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c index 0c56a0d20b29..c927324fdd26 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/utilities/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -276,7 +276,7 @@ acpi_ut_short_divide(acpi_integer in_dividend, *out_quotient = in_dividend / divisor; } if (out_remainder) { - *out_remainder = (u32) in_dividend % divisor; + *out_remainder = (u32) (in_dividend % divisor); } return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 2d19f71e9cfa..e4ba7192cd15 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1033,6 +1033,7 @@ acpi_ut_error(char *module_name, u32 line_number, char *format, ...) va_start(args, format); acpi_os_vprintf(format, args); acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + va_end(args); } void ACPI_INTERNAL_VAR_XFACE @@ -1061,6 +1062,8 @@ acpi_ut_warning(char *module_name, u32 line_number, char *format, ...) va_start(args, format); acpi_os_vprintf(format, args); acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + va_end(args); + va_end(args); } void ACPI_INTERNAL_VAR_XFACE @@ -1077,4 +1080,5 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...) va_start(args, format); acpi_os_vprintf(format, args); acpi_os_printf("\n"); + va_end(args); } diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index 4820bc86d1f5..f7d602b1a894 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index e08b3fa6639f..e68466de8044 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -107,6 +107,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name, switch (type) { case ACPI_TYPE_REGION: case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: /* These types require a secondary object */ @@ -469,9 +470,8 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_POWER: - /* - * No extra data for these types - */ + /* No extra data for these types */ + break; case ACPI_TYPE_LOCAL_REFERENCE: diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index b630ee137ee1..c3e3e1308edc 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index edcaafad0a31..63a6d3d77d88 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 2d496918b3cd..f8bdadf3c32f 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2007, R. Byron Moore + * Copyright (C) 2000 - 2008, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,7 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utxface") +#ifndef ACPI_ASL_COMPILER /******************************************************************************* * * FUNCTION: acpi_initialize_subsystem @@ -192,24 +193,6 @@ acpi_status acpi_enable_subsystem(u32 flags) } } - /* - * Complete the GPE initialization for the GPE blocks defined in the FADT - * (GPE block 0 and 1). - * - * Note1: This is where the _PRW methods are executed for the GPEs. These - * methods can only be executed after the SCI and Global Lock handlers are - * installed and initialized. - * - * Note2: Currently, there seems to be no need to run the _REG methods - * before execution of the _PRW methods and enabling of the GPEs. - */ - if (!(flags & ACPI_NO_EVENT_INIT)) { - status = acpi_ev_install_fadt_gpes(); - if (ACPI_FAILURE(status)) { - return (status); - } - } - return_ACPI_STATUS(status); } @@ -280,6 +263,23 @@ acpi_status acpi_initialize_objects(u32 flags) } /* + * Complete the GPE initialization for the GPE blocks defined in the FADT + * (GPE block 0 and 1). + * + * Note1: This is where the _PRW methods are executed for the GPEs. These + * methods can only be executed after the SCI and Global Lock handlers are + * installed and initialized. + * + * Note2: Currently, there seems to be no need to run the _REG methods + * before execution of the _PRW methods and enabling of the GPEs. + */ + if (!(flags & ACPI_NO_EVENT_INIT)) { + status = acpi_ev_install_fadt_gpes(); + if (ACPI_FAILURE(status)) + return (status); + } + + /* * Empty the caches (delete the cached objects) on the assumption that * the table load filled them up more than they will be at runtime -- * thus wasting non-paged memory. @@ -292,6 +292,7 @@ acpi_status acpi_initialize_objects(u32 flags) ACPI_EXPORT_SYMBOL(acpi_initialize_objects) +#endif /******************************************************************************* * * FUNCTION: acpi_terminate @@ -335,6 +336,7 @@ acpi_status acpi_terminate(void) } ACPI_EXPORT_SYMBOL(acpi_terminate) +#ifndef ACPI_ASL_COMPILER #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -490,3 +492,4 @@ acpi_status acpi_purge_cached_objects(void) } ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects) +#endif diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 44ea60cf21c0..100926143818 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -398,7 +398,7 @@ acpi_evaluate_reference(acpi_handle handle, element = &(package->package.elements[i]); - if (element->type != ACPI_TYPE_ANY) { + if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { status = AE_BAD_DATA; printk(KERN_ERR PREFIX "Expecting a [Reference] package element, found type %X\n", diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 980a74188781..5e5dda3a3027 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -57,8 +57,6 @@ #define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88 #define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89 -#define ACPI_VIDEO_HEAD_INVALID (~0u - 1) -#define ACPI_VIDEO_HEAD_END (~0u) #define MAX_NAME_LEN 20 #define ACPI_VIDEO_DISPLAY_CRT 1 @@ -192,6 +190,7 @@ struct acpi_video_device { /* bus */ static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -200,6 +199,7 @@ static struct file_operations acpi_video_bus_info_fops = { static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_ROM_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_ROM_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -209,6 +209,7 @@ static struct file_operations acpi_video_bus_ROM_fops = { static int acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_POST_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_POST_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -217,6 +218,7 @@ static struct file_operations acpi_video_bus_POST_info_fops = { static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_POST_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_POST_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -225,6 +227,7 @@ static struct file_operations acpi_video_bus_POST_fops = { static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_DOS_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_DOS_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -235,6 +238,7 @@ static struct file_operations acpi_video_bus_DOS_fops = { static int acpi_video_device_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -244,6 +248,7 @@ static struct file_operations acpi_video_device_info_fops = { static int acpi_video_device_state_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_state_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -253,6 +258,7 @@ static struct file_operations acpi_video_device_state_fops = { static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_brightness_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_brightness_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -262,6 +268,7 @@ static struct file_operations acpi_video_device_brightness_fops = { static int acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_EDID_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_EDID_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -734,21 +741,19 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (IS_ERR(device->cdev)) return; - if (device->cdev) { - printk(KERN_INFO PREFIX - "%s is registered as cooling_device%d\n", - device->dev->dev.bus_id, device->cdev->id); - result = sysfs_create_link(&device->dev->dev.kobj, - &device->cdev->device.kobj, - "thermal_cooling"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); - result = sysfs_create_link(&device->cdev->device.kobj, - &device->dev->dev.kobj, - "device"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); - } + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev->dev.bus_id, device->cdev->id); + result = sysfs_create_link(&device->dev->dev.kobj, + &device->cdev->device.kobj, + "thermal_cooling"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + result = sysfs_create_link(&device->cdev->device.kobj, + &device->dev->dev.kobj, "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + } if (device->cap._DCS && device->cap._DSS){ static int count = 0; @@ -1050,87 +1055,82 @@ acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file) static int acpi_video_device_add_fs(struct acpi_device *device) { - struct proc_dir_entry *entry = NULL; + struct proc_dir_entry *entry, *device_dir; struct acpi_video_device *vid_dev; - - if (!device) - return -ENODEV; - vid_dev = acpi_driver_data(device); if (!vid_dev) return -ENODEV; - if (!acpi_device_dir(device)) { - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), - vid_dev->video->dir); - if (!acpi_device_dir(device)) - return -ENODEV; - acpi_device_dir(device)->owner = THIS_MODULE; - } + device_dir = proc_mkdir(acpi_device_bid(device), + vid_dev->video->dir); + if (!device_dir) + return -ENOMEM; + + device_dir->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("info", S_IRUGO, device_dir, + &acpi_video_device_info_fops, acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_video_device_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_dir; /* 'state' [R/W] */ - entry = - create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + acpi_video_device_state_fops.write = acpi_video_device_write_state; + entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, + device_dir, + &acpi_video_device_state_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - acpi_video_device_state_fops.write = acpi_video_device_write_state; - entry->proc_fops = &acpi_video_device_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_info; /* 'brightness' [R/W] */ - entry = - create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + acpi_video_device_brightness_fops.write = + acpi_video_device_write_brightness; + entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, + device_dir, + &acpi_video_device_brightness_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness; - entry->proc_fops = &acpi_video_device_brightness_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_state; /* 'EDID' [R] */ - entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("EDID", S_IRUGO, device_dir, + &acpi_video_device_EDID_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_video_device_EDID_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_brightness; + + acpi_device_dir(device) = device_dir; return 0; + + err_remove_brightness: + remove_proc_entry("brightness", device_dir); + err_remove_state: + remove_proc_entry("state", device_dir); + err_remove_info: + remove_proc_entry("info", device_dir); + err_remove_dir: + remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); + return -ENOMEM; } static int acpi_video_device_remove_fs(struct acpi_device *device) { struct acpi_video_device *vid_dev; + struct proc_dir_entry *device_dir; vid_dev = acpi_driver_data(device); if (!vid_dev || !vid_dev->video || !vid_dev->video->dir) return -ENODEV; - if (acpi_device_dir(device)) { - remove_proc_entry("info", acpi_device_dir(device)); - remove_proc_entry("state", acpi_device_dir(device)); - remove_proc_entry("brightness", acpi_device_dir(device)); - remove_proc_entry("EDID", acpi_device_dir(device)); + device_dir = acpi_device_dir(device); + if (device_dir) { + remove_proc_entry("info", device_dir); + remove_proc_entry("state", device_dir); + remove_proc_entry("brightness", device_dir); + remove_proc_entry("EDID", device_dir); remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); acpi_device_dir(device) = NULL; } @@ -1337,94 +1337,81 @@ acpi_video_bus_write_DOS(struct file *file, static int acpi_video_bus_add_fs(struct acpi_device *device) { - struct proc_dir_entry *entry = NULL; - struct acpi_video_bus *video; + struct acpi_video_bus *video = acpi_driver_data(device); + struct proc_dir_entry *device_dir; + struct proc_dir_entry *entry; + device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir); + if (!device_dir) + return -ENOMEM; - video = acpi_driver_data(device); - - if (!acpi_device_dir(device)) { - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), - acpi_video_dir); - if (!acpi_device_dir(device)) - return -ENODEV; - video->dir = acpi_device_dir(device); - acpi_device_dir(device)->owner = THIS_MODULE; - } + device_dir->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("info", S_IRUGO, device_dir, + &acpi_video_bus_info_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_dir; /* 'ROM' [R] */ - entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("ROM", S_IRUGO, device_dir, + &acpi_video_bus_ROM_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_ROM_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_info; /* 'POST_info' [R] */ - entry = - create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("POST_info", S_IRUGO, device_dir, + &acpi_video_bus_POST_info_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_POST_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_rom; /* 'POST' [R/W] */ - entry = - create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR, - acpi_device_dir(device)); + acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; + entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR, + device_dir, + &acpi_video_bus_POST_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; - entry->proc_fops = &acpi_video_bus_POST_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_post_info; /* 'DOS' [R/W] */ - entry = - create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR, - acpi_device_dir(device)); + acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; + entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR, + device_dir, + &acpi_video_bus_DOS_fops, + acpi_driver_data(device)); if (!entry) - return -ENODEV; - else { - acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; - entry->proc_fops = &acpi_video_bus_DOS_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + goto err_remove_post; + video->dir = acpi_device_dir(device) = device_dir; return 0; + + err_remove_post: + remove_proc_entry("POST", device_dir); + err_remove_post_info: + remove_proc_entry("POST_info", device_dir); + err_remove_rom: + remove_proc_entry("ROM", device_dir); + err_remove_info: + remove_proc_entry("info", device_dir); + err_remove_dir: + remove_proc_entry(acpi_device_bid(device), acpi_video_dir); + return -ENOMEM; } static int acpi_video_bus_remove_fs(struct acpi_device *device) { - struct acpi_video_bus *video; + struct proc_dir_entry *device_dir = acpi_device_dir(device); - - video = acpi_driver_data(device); - - if (acpi_device_dir(device)) { - remove_proc_entry("info", acpi_device_dir(device)); - remove_proc_entry("ROM", acpi_device_dir(device)); - remove_proc_entry("POST_info", acpi_device_dir(device)); - remove_proc_entry("POST", acpi_device_dir(device)); - remove_proc_entry("DOS", acpi_device_dir(device)); + if (device_dir) { + remove_proc_entry("info", device_dir); + remove_proc_entry("ROM", device_dir); + remove_proc_entry("POST_info", device_dir); + remove_proc_entry("POST", device_dir); + remove_proc_entry("DOS", device_dir); remove_proc_entry(acpi_device_bid(device), acpi_video_dir); acpi_device_dir(device) = NULL; } @@ -1440,11 +1427,15 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device) static struct acpi_video_device_attrib* acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) { - int count; + struct acpi_video_enumerated_device *ids; + int i; + + for (i = 0; i < video->attached_count; i++) { + ids = &video->attached_array[i]; + if ((ids->value.int_val & 0xffff) == device_id) + return &ids->value.attrib; + } - for(count = 0; count < video->attached_count; count++) - if((video->attached_array[count].value.int_val & 0xffff) == device_id) - return &(video->attached_array[count].value.attrib); return NULL; } @@ -1571,20 +1562,16 @@ static void acpi_video_device_bind(struct acpi_video_bus *video, struct acpi_video_device *device) { + struct acpi_video_enumerated_device *ids; int i; -#define IDS_VAL(i) video->attached_array[i].value.int_val -#define IDS_BIND(i) video->attached_array[i].bind_info - - for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID && - i < video->attached_count; i++) { - if (device->device_id == (IDS_VAL(i) & 0xffff)) { - IDS_BIND(i) = device; + for (i = 0; i < video->attached_count; i++) { + ids = &video->attached_array[i]; + if (device->device_id == (ids->value.int_val & 0xffff)) { + ids->bind_info = device; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i)); } } -#undef IDS_VAL -#undef IDS_BIND } /* @@ -1603,7 +1590,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) int status; int count; int i; - struct acpi_video_enumerated_device *active_device_list; + struct acpi_video_enumerated_device *active_list; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *dod = NULL; union acpi_object *obj; @@ -1624,13 +1611,10 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n", dod->package.count)); - active_device_list = kmalloc((1 + - dod->package.count) * - sizeof(struct - acpi_video_enumerated_device), - GFP_KERNEL); - - if (!active_device_list) { + active_list = kcalloc(1 + dod->package.count, + sizeof(struct acpi_video_enumerated_device), + GFP_KERNEL); + if (!active_list) { status = -ENOMEM; goto out; } @@ -1640,23 +1624,24 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) obj = &dod->package.elements[i]; if (obj->type != ACPI_TYPE_INTEGER) { - printk(KERN_ERR PREFIX "Invalid _DOD data\n"); - active_device_list[i].value.int_val = - ACPI_VIDEO_HEAD_INVALID; + printk(KERN_ERR PREFIX + "Invalid _DOD data in element %d\n", i); + continue; } - active_device_list[i].value.int_val = obj->integer.value; - active_device_list[i].bind_info = NULL; + + active_list[count].value.int_val = obj->integer.value; + active_list[count].bind_info = NULL; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, (int)obj->integer.value)); count++; } - active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END; kfree(video->attached_array); - video->attached_array = active_device_list; + video->attached_array = active_list; video->attached_count = count; - out: + + out: kfree(buffer.pointer); return status; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 292aa9a0f02f..1c11df9a5f32 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -566,11 +566,11 @@ config PATA_RADISYS If unsure, say N. -config PATA_RB500 - tristate "RouterBoard 500 PATA CompactFlash support" - depends on MIKROTIK_RB500 +config PATA_RB532 + tristate "RouterBoard 532 PATA CompactFlash support" + depends on MIKROTIK_RB532 help - This option enables support for the RouterBoard 500 + This option enables support for the RouterBoard 532 PATA CompactFlash controller. If unsure, say N. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 1fbc2aa648b7..b693d829383a 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,7 +55,7 @@ obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o -obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o +obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7c4f886f1f16..8cace9aa9c03 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -358,7 +358,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_sb600 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY | + AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 51b7d2fad36a..3bc488538204 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3933,6 +3933,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices which get the IVB wrong */ { "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, }, + /* Maybe we should just blacklist TSSTcorp... */ + { "TSSTcorp CDDVDW SH-S202H", "SB00", ATA_HORKAGE_IVB, }, + { "TSSTcorp CDDVDW SH-S202H", "SB01", ATA_HORKAGE_IVB, }, { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, }, { "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, }, { "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, }, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a34f32442edf..3ce43920e459 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -49,7 +49,11 @@ #include "libata.h" -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 +#define ATA_SCSI_RBUF_SIZE 4096 + +static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); +static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); @@ -179,6 +183,13 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ata_scsi_lpm_show, ata_scsi_lpm_put); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); +static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); +} + static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -1632,53 +1643,48 @@ defer: /** * ata_scsi_rbuf_get - Map response buffer. - * @cmd: SCSI command containing buffer to be mapped. - * @buf_out: Pointer to mapped area. + * @flags: unsigned long variable to store irq enable status + * @copy_in: copy in from user buffer * - * Maps buffer contained within SCSI command @cmd. + * Prepare buffer for simulated SCSI commands. * * LOCKING: - * spin_lock_irqsave(host lock) + * spin_lock_irqsave(ata_scsi_rbuf_lock) on success * * RETURNS: - * Length of response buffer. + * Pointer to response buffer. */ - -static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) +static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in, + unsigned long *flags) { - u8 *buf; - unsigned int buflen; - - struct scatterlist *sg = scsi_sglist(cmd); + spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags); - if (sg) { - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - buflen = sg->length; - } else { - buf = NULL; - buflen = 0; - } - - *buf_out = buf; - return buflen; + memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); + if (copy_in) + sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + return ata_scsi_rbuf; } /** * ata_scsi_rbuf_put - Unmap response buffer. * @cmd: SCSI command containing buffer to be unmapped. - * @buf: buffer to unmap + * @copy_out: copy out result + * @flags: @flags passed to ata_scsi_rbuf_get() * - * Unmaps response buffer contained within @cmd. + * Returns rbuf buffer. The result is copied to @cmd's buffer if + * @copy_back is true. * * LOCKING: - * spin_lock_irqsave(host lock) + * Unlocks ata_scsi_rbuf_lock. */ - -static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) +static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, + unsigned long *flags) { - struct scatterlist *sg = scsi_sglist(cmd); - if (sg) - kunmap_atomic(buf - sg->offset, KM_IRQ0); + if (copy_out) + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags); } /** @@ -1696,24 +1702,17 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) * LOCKING: * spin_lock_irqsave(host lock) */ - -void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor) (struct ata_scsi_args *args, - u8 *rbuf, unsigned int buflen)) +static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, + unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) { u8 *rbuf; - unsigned int buflen, rc; + unsigned int rc; struct scsi_cmnd *cmd = args->cmd; unsigned long flags; - local_irq_save(flags); - - buflen = ata_scsi_rbuf_get(cmd, &rbuf); - memset(rbuf, 0, buflen); - rc = actor(args, rbuf, buflen); - ata_scsi_rbuf_put(cmd, rbuf); - - local_irq_restore(flags); + rbuf = ata_scsi_rbuf_get(cmd, false, &flags); + rc = actor(args, rbuf); + ata_scsi_rbuf_put(cmd, rc == 0, &flags); if (rc == 0) cmd->result = SAM_STAT_GOOD; @@ -1721,26 +1720,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, } /** - * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer - * @idx: byte index into SCSI response buffer - * @val: value to set - * - * To be used by SCSI command simulator functions. This macros - * expects two local variables, u8 *rbuf and unsigned int buflen, - * are in scope. - * - * LOCKING: - * None. - */ -#define ATA_SCSI_RBUF_SET(idx, val) do { \ - if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \ - } while (0) - -/** * ata_scsiop_inq_std - Simulate INQUIRY command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns standard device identification data associated * with non-VPD INQUIRY command output. @@ -1748,10 +1730,17 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) { + const u8 versions[] = { + 0x60, /* SAM-3 (no version claimed) */ + + 0x03, + 0x20, /* SBC-2 (no version claimed) */ + + 0x02, + 0x60 /* SPC-3 (no version claimed) */ + }; u8 hdr[] = { TYPE_DISK, 0, @@ -1760,35 +1749,21 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, 95 - 4 }; + VPRINTK("ENTER\n"); + /* set scsi removeable (RMB) bit per ata bit */ if (ata_id_removeable(args->id)) hdr[1] |= (1 << 7); - VPRINTK("ENTER\n"); - memcpy(rbuf, hdr, sizeof(hdr)); + memcpy(&rbuf[8], "ATA ", 8); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); - if (buflen > 35) { - memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); - if (rbuf[32] == 0 || rbuf[32] == ' ') - memcpy(&rbuf[32], "n/a ", 4); - } - - if (buflen > 63) { - const u8 versions[] = { - 0x60, /* SAM-3 (no version claimed) */ - - 0x03, - 0x20, /* SBC-2 (no version claimed) */ + if (rbuf[32] == 0 || rbuf[32] == ' ') + memcpy(&rbuf[32], "n/a ", 4); - 0x02, - 0x60 /* SPC-3 (no version claimed) */ - }; - - memcpy(rbuf + 59, versions, sizeof(versions)); - } + memcpy(rbuf + 59, versions, sizeof(versions)); return 0; } @@ -1797,27 +1772,22 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns list of inquiry VPD pages available. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) { const u8 pages[] = { 0x00, /* page 0x00, this page */ 0x80, /* page 0x80, unit serial no page */ 0x83 /* page 0x83, device ident page */ }; - rbuf[3] = sizeof(pages); /* number of supported VPD pages */ - - if (buflen > 6) - memcpy(rbuf + 4, pages, sizeof(pages)); + rbuf[3] = sizeof(pages); /* number of supported VPD pages */ + memcpy(rbuf + 4, pages, sizeof(pages)); return 0; } @@ -1825,16 +1795,13 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns ATA device serial number. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) { const u8 hdr[] = { 0, @@ -1842,12 +1809,10 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, 0, ATA_ID_SERNO_LEN, /* page len */ }; - memcpy(rbuf, hdr, sizeof(hdr)); - - if (buflen > (ATA_ID_SERNO_LEN + 4 - 1)) - ata_id_string(args->id, (unsigned char *) &rbuf[4], - ATA_ID_SERNO, ATA_ID_SERNO_LEN); + memcpy(rbuf, hdr, sizeof(hdr)); + ata_id_string(args->id, (unsigned char *) &rbuf[4], + ATA_ID_SERNO, ATA_ID_SERNO_LEN); return 0; } @@ -1855,7 +1820,6 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Yields two logical unit device identification designators: * - vendor specific ASCII containing the ATA serial number @@ -1865,41 +1829,37 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) { - int num; const int sat_model_serial_desc_len = 68; + int num; rbuf[1] = 0x83; /* this page code */ num = 4; - if (buflen > (ATA_ID_SERNO_LEN + num + 3)) { - /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ - rbuf[num + 0] = 2; - rbuf[num + 3] = ATA_ID_SERNO_LEN; - num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO, ATA_ID_SERNO_LEN); - num += ATA_ID_SERNO_LEN; - } - if (buflen > (sat_model_serial_desc_len + num + 3)) { - /* SAT defined lu model and serial numbers descriptor */ - /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */ - rbuf[num + 0] = 2; - rbuf[num + 1] = 1; - rbuf[num + 3] = sat_model_serial_desc_len; - num += 4; - memcpy(rbuf + num, "ATA ", 8); - num += 8; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_PROD, ATA_ID_PROD_LEN); - num += ATA_ID_PROD_LEN; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO, ATA_ID_SERNO_LEN); - num += ATA_ID_SERNO_LEN; - } + /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ + rbuf[num + 0] = 2; + rbuf[num + 3] = ATA_ID_SERNO_LEN; + num += 4; + ata_id_string(args->id, (unsigned char *) rbuf + num, + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; + + /* SAT defined lu model and serial numbers descriptor */ + /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */ + rbuf[num + 0] = 2; + rbuf[num + 1] = 1; + rbuf[num + 3] = sat_model_serial_desc_len; + num += 4; + memcpy(rbuf + num, "ATA ", 8); + num += 8; + ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD, + ATA_ID_PROD_LEN); + num += ATA_ID_PROD_LEN; + ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, + ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; + rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ return 0; } @@ -1908,35 +1868,26 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Yields SAT-specified ATA VPD page. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) { - u8 pbuf[60]; struct ata_taskfile tf; - unsigned int i; - if (!buflen) - return 0; - - memset(&pbuf, 0, sizeof(pbuf)); memset(&tf, 0, sizeof(tf)); - pbuf[1] = 0x89; /* our page code */ - pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ - pbuf[3] = (0x238 & 0xff); + rbuf[1] = 0x89; /* our page code */ + rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ + rbuf[3] = (0x238 & 0xff); - memcpy(&pbuf[8], "linux ", 8); - memcpy(&pbuf[16], "libata ", 16); - memcpy(&pbuf[32], DRV_VERSION, 4); - ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); + memcpy(&rbuf[8], "linux ", 8); + memcpy(&rbuf[16], "libata ", 16); + memcpy(&rbuf[32], DRV_VERSION, 4); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); /* we don't store the ATA device signature, so we fake it */ @@ -1944,19 +1895,12 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, tf.lbal = 0x1; tf.nsect = 0x1; - ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */ - pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ + ata_tf_to_fis(&tf, 0, 1, &rbuf[36]); /* TODO: PMP? */ + rbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ - pbuf[56] = ATA_CMD_ID_ATA; + rbuf[56] = ATA_CMD_ID_ATA; - i = min(buflen, 60U); - memcpy(rbuf, &pbuf[0], i); - buflen -= i; - - if (!buflen) - return 0; - - memcpy(&rbuf[60], &args->id[0], min(buflen, 512U)); + memcpy(&rbuf[60], &args->id[0], 512); return 0; } @@ -1964,7 +1908,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * No operation. Simply returns success to caller, to indicate * that the caller should successfully complete this SCSI command. @@ -1972,47 +1915,16 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) { VPRINTK("ENTER\n"); return 0; } /** - * ata_msense_push - Push data onto MODE SENSE data output buffer - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer - * @buf: Pointer to BLOB being added to output buffer - * @buflen: Length of BLOB - * - * Store MODE SENSE data on an output buffer. - * - * LOCKING: - * None. - */ - -static void ata_msense_push(u8 **ptr_io, const u8 *last, - const u8 *buf, unsigned int buflen) -{ - u8 *ptr = *ptr_io; - - if ((ptr + buflen - 1) > last) - return; - - memcpy(ptr, buf, buflen); - - ptr += buflen; - - *ptr_io = ptr; -} - -/** * ata_msense_caching - Simulate MODE SENSE caching info page * @id: device IDENTIFY data - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @buf: output buffer * * Generate a caching info page, which conditionally indicates * write caching to the SCSI layer, depending on device @@ -2021,58 +1933,43 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, * LOCKING: * None. */ - -static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, - const u8 *last) +static unsigned int ata_msense_caching(u16 *id, u8 *buf) { - u8 page[CACHE_MPAGE_LEN]; - - memcpy(page, def_cache_mpage, sizeof(page)); + memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage)); if (ata_id_wcache_enabled(id)) - page[2] |= (1 << 2); /* write cache enable */ + buf[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) - page[12] |= (1 << 5); /* disable read ahead */ - - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + buf[12] |= (1 << 5); /* disable read ahead */ + return sizeof(def_cache_mpage); } /** * ata_msense_ctl_mode - Simulate MODE SENSE control mode page - * @dev: Device associated with this MODE SENSE command - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @buf: output buffer * * Generate a generic MODE SENSE control mode page. * * LOCKING: * None. */ - -static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) +static unsigned int ata_msense_ctl_mode(u8 *buf) { - ata_msense_push(ptr_io, last, def_control_mpage, - sizeof(def_control_mpage)); + memcpy(buf, def_control_mpage, sizeof(def_control_mpage)); return sizeof(def_control_mpage); } /** * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page - * @dev: Device associated with this MODE SENSE command - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @bufp: output buffer * * Generate a generic MODE SENSE r/w error recovery page. * * LOCKING: * None. */ - -static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) +static unsigned int ata_msense_rw_recovery(u8 *buf) { - - ata_msense_push(ptr_io, last, def_rw_recovery_mpage, - sizeof(def_rw_recovery_mpage)); + memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage)); return sizeof(def_rw_recovery_mpage); } @@ -2104,7 +2001,6 @@ static int ata_dev_supports_fua(u16 *id) * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate MODE SENSE commands. Assume this is invoked for direct * access devices (e.g. disks) only. There should be no block @@ -2113,19 +2009,17 @@ static int ata_dev_supports_fua(u16 *id) * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) { struct ata_device *dev = args->dev; - u8 *scsicmd = args->cmd->cmnd, *p, *last; + u8 *scsicmd = args->cmd->cmnd, *p = rbuf; const u8 sat_blk_desc[] = { 0, 0, 0, 0, /* number of blocks: sat unspecified */ 0, 0, 0x2, 0x0 /* block length: 512 bytes */ }; u8 pg, spg; - unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; + unsigned int ebd, page_control, six_byte; u8 dpofua; VPRINTK("ENTER\n"); @@ -2148,17 +2042,10 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } - if (six_byte) { - output_len = 4 + (ebd ? 8 : 0); - alloc_len = scsicmd[4]; - } else { - output_len = 8 + (ebd ? 8 : 0); - alloc_len = (scsicmd[7] << 8) + scsicmd[8]; - } - minlen = (alloc_len < buflen) ? alloc_len : buflen; - - p = rbuf + output_len; - last = rbuf + minlen - 1; + if (six_byte) + p += 4 + (ebd ? 8 : 0); + else + p += 8 + (ebd ? 8 : 0); pg = scsicmd[2] & 0x3f; spg = scsicmd[3]; @@ -2171,61 +2058,48 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, switch(pg) { case RW_RECOVERY_MPAGE: - output_len += ata_msense_rw_recovery(&p, last); + p += ata_msense_rw_recovery(p); break; case CACHE_MPAGE: - output_len += ata_msense_caching(args->id, &p, last); + p += ata_msense_caching(args->id, p); break; - case CONTROL_MPAGE: { - output_len += ata_msense_ctl_mode(&p, last); + case CONTROL_MPAGE: + p += ata_msense_ctl_mode(p); break; - } case ALL_MPAGES: - output_len += ata_msense_rw_recovery(&p, last); - output_len += ata_msense_caching(args->id, &p, last); - output_len += ata_msense_ctl_mode(&p, last); + p += ata_msense_rw_recovery(p); + p += ata_msense_caching(args->id, p); + p += ata_msense_ctl_mode(p); break; default: /* invalid page code */ goto invalid_fld; } - if (minlen < 1) - return 0; - dpofua = 0; if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) && (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count)) dpofua = 1 << 4; if (six_byte) { - output_len--; - rbuf[0] = output_len; - if (minlen > 2) - rbuf[2] |= dpofua; + rbuf[0] = p - rbuf - 1; + rbuf[2] |= dpofua; if (ebd) { - if (minlen > 3) - rbuf[3] = sizeof(sat_blk_desc); - if (minlen > 11) - memcpy(rbuf + 4, sat_blk_desc, - sizeof(sat_blk_desc)); + rbuf[3] = sizeof(sat_blk_desc); + memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc)); } } else { - output_len -= 2; + unsigned int output_len = p - rbuf - 2; + rbuf[0] = output_len >> 8; - if (minlen > 1) - rbuf[1] = output_len; - if (minlen > 3) - rbuf[3] |= dpofua; + rbuf[1] = output_len; + rbuf[3] |= dpofua; if (ebd) { - if (minlen > 7) - rbuf[7] = sizeof(sat_blk_desc); - if (minlen > 15) - memcpy(rbuf + 8, sat_blk_desc, - sizeof(sat_blk_desc)); + rbuf[7] = sizeof(sat_blk_desc); + memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); } } return 0; @@ -2245,15 +2119,13 @@ saving_not_supp: * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate READ CAPACITY commands. * * LOCKING: * None. */ -unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) { u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */ @@ -2264,28 +2136,28 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, last_lba = 0xffffffff; /* sector count, 32-bit */ - ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3)); - ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2)); - ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1)); - ATA_SCSI_RBUF_SET(3, last_lba); + rbuf[0] = last_lba >> (8 * 3); + rbuf[1] = last_lba >> (8 * 2); + rbuf[2] = last_lba >> (8 * 1); + rbuf[3] = last_lba; /* sector size */ - ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff); + rbuf[6] = ATA_SECT_SIZE >> 8; + rbuf[7] = ATA_SECT_SIZE & 0xff; } else { /* sector count, 64-bit */ - ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); - ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6)); - ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5)); - ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4)); - ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3)); - ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2)); - ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1)); - ATA_SCSI_RBUF_SET(7, last_lba); + rbuf[0] = last_lba >> (8 * 7); + rbuf[1] = last_lba >> (8 * 6); + rbuf[2] = last_lba >> (8 * 5); + rbuf[3] = last_lba >> (8 * 4); + rbuf[4] = last_lba >> (8 * 3); + rbuf[5] = last_lba >> (8 * 2); + rbuf[6] = last_lba >> (8 * 1); + rbuf[7] = last_lba; /* sector size */ - ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff); + rbuf[10] = ATA_SECT_SIZE >> 8; + rbuf[11] = ATA_SECT_SIZE & 0xff; } return 0; @@ -2295,16 +2167,13 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_report_luns - Simulate REPORT LUNS command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate REPORT LUNS command. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf) { VPRINTK("ENTER\n"); rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */ @@ -2312,53 +2181,6 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, return 0; } -/** - * ata_scsi_set_sense - Set SCSI sense data and status - * @cmd: SCSI request to be handled - * @sk: SCSI-defined sense key - * @asc: SCSI-defined additional sense code - * @ascq: SCSI-defined additional sense code qualifier - * - * Helper function that builds a valid fixed format, current - * response code and the given sense key (sk), additional sense - * code (asc) and additional sense code qualifier (ascq) with - * a SCSI command status of %SAM_STAT_CHECK_CONDITION and - * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . - * - * LOCKING: - * Not required - */ - -void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) -{ - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); -} - -/** - * ata_scsi_badcmd - End a SCSI request with an error - * @cmd: SCSI request to be handled - * @done: SCSI command completion function - * @asc: SCSI-defined additional sense code - * @ascq: SCSI-defined additional sense code qualifier - * - * Helper function that completes a SCSI command with - * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST - * and the specified additional sense codes. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) -{ - DPRINTK("ENTER\n"); - ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); - - done(cmd); -} - static void atapi_sense_complete(struct ata_queued_cmd *qc) { if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) { @@ -2485,13 +2307,10 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) u8 *scsicmd = cmd->cmnd; if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) { - u8 *buf = NULL; - unsigned int buflen; unsigned long flags; + u8 *buf; - local_irq_save(flags); - - buflen = ata_scsi_rbuf_get(cmd, &buf); + buf = ata_scsi_rbuf_get(cmd, true, &flags); /* ATAPI devices typically report zero for their SCSI version, * and sometimes deviate from the spec WRT response data @@ -2506,9 +2325,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) buf[3] = 0x32; } - ata_scsi_rbuf_put(cmd, buf); - - local_irq_restore(flags); + ata_scsi_rbuf_put(cmd, true, &flags); } cmd->result = SAM_STAT_GOOD; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ae2cfd95d43e..4514283937ea 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -146,34 +146,6 @@ extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); -extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); - -extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); - -extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *), - u8 asc, u8 ascq); -extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, - u8 sk, u8 asc, u8 ascq); -extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor) (struct ata_scsi_args *args, - u8 *rbuf, unsigned int buflen)); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 78738fb4223b..d7de7baf58a8 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -88,8 +88,8 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data); pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); - pio_mode_data &= ~(0xFF << timing_shift); - pio_mode_data |= (pio_timings[pio] << timing_shift); + pio_timing_data &= ~(0xFF << timing_shift); + pio_timing_data |= (pio_timings[pio] << timing_shift); pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); } diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index a75de0684c15..9ab89732cf94 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1272,8 +1272,8 @@ static void bfin_freeze(struct ata_port *ap) void bfin_thaw(struct ata_port *ap) { + dev_dbg(ap->dev, "in atapi dma thaw\n"); bfin_check_status(ap); - bfin_irq_clear(ap); bfin_irq_on(ap); } @@ -1339,13 +1339,130 @@ static int bfin_port_start(struct ata_port *ap) return 0; } +static unsigned int bfin_ata_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc) +{ + struct ata_eh_info *ehi = &ap->link.eh_info; + u8 status, host_stat = 0; + + VPRINTK("ata%u: protocol %d task_state %d\n", + ap->print_id, qc->tf.protocol, ap->hsm_task_state); + + /* Check whether we are expecting interrupt in this state */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + + /* Check the ATA_DFLAG_CDB_INTR flag is enough here. + * The flag was turned on only for atapi devices. + * No need to check is_atapi_taskfile(&qc->tf) again. + */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + goto idle_irq; + break; + case HSM_ST_LAST: + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA) { + /* check status of DMA engine */ + host_stat = ap->ops->bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", + ap->print_id, host_stat); + + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; + + /* before we do anything else, clear DMA-Start bit */ + ap->ops->bmdma_stop(qc); + + if (unlikely(host_stat & ATA_DMA_ERR)) { + /* error when transfering data to/from memory */ + qc->err_mask |= AC_ERR_HOST_BUS; + ap->hsm_task_state = HSM_ST_ERR; + } + } + break; + case HSM_ST: + break; + default: + goto idle_irq; + } + + /* check altstatus */ + status = ap->ops->sff_check_altstatus(ap); + if (status & ATA_BUSY) + goto busy_ata; + + /* check main status, clearing INTRQ */ + status = ap->ops->sff_check_status(ap); + if (unlikely(status & ATA_BUSY)) + goto busy_ata; + + /* ack bmdma irq events */ + ap->ops->sff_irq_clear(ap); + + ata_sff_hsm_move(ap, qc, status, 0); + + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + +busy_ata: + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; + +#ifdef ATA_IRQ_TRAP + if ((ap->stats.idle_irq % 1000) == 0) { + ap->ops->irq_ack(ap, 0); /* debug trap */ + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); + return 1; + } +#endif + return 0; /* irq not handled */ +} + +static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + + /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ + spin_lock_irqsave(&host->lock, flags); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap; + + ap = host->ports[i]; + if (ap && + !(ap->flags & ATA_FLAG_DISABLED)) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->link.active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && + (qc->flags & ATA_QCFLAG_ACTIVE)) + handled |= bfin_ata_host_intr(ap, qc); + } + } + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_RETVAL(handled); +} + + static struct scsi_host_template bfin_sht = { ATA_BASE_SHT(DRV_NAME), .sg_tablesize = SG_NONE, .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations bfin_pata_ops = { +static struct ata_port_operations bfin_pata_ops = { .inherits = &ata_sff_port_ops, .set_piomode = bfin_set_piomode, @@ -1370,7 +1487,6 @@ static const struct ata_port_operations bfin_pata_ops = { .thaw = bfin_thaw, .softreset = bfin_softreset, .postreset = bfin_postreset, - .post_internal_cmd = bfin_bmdma_stop, .sff_irq_clear = bfin_irq_clear, .sff_irq_on = bfin_irq_on, @@ -1507,7 +1623,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev) } if (ata_host_activate(host, platform_get_irq(pdev, 0), - ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { peripheral_free_list(atapi_io_port); dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); return -ENODEV; diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb532_cf.c index 4345174aaeec..a108d259f19d 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -32,7 +32,7 @@ #include <asm/gpio.h> -#define DRV_NAME "pata-rb500-cf" +#define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" @@ -43,7 +43,7 @@ #define RB500_CF_REG_CTRL 0x080E #define RB500_CF_REG_DATA 0x0C00 -struct rb500_cf_info { +struct rb532_cf_info { void __iomem *iobase; unsigned int gpio_line; int frozen; @@ -52,10 +52,10 @@ struct rb500_cf_info { /* ------------------------------------------------------------------------ */ -static inline void rb500_pata_finish_io(struct ata_port *ap) +static inline void rb532_pata_finish_io(struct ata_port *ap) { struct ata_host *ah = ap->host; - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; ata_sff_altstatus(ap); ndelay(RB500_CF_IO_DELAY); @@ -63,14 +63,14 @@ static inline void rb500_pata_finish_io(struct ata_port *ap) set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); } -static void rb500_pata_exec_command(struct ata_port *ap, +static void rb532_pata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { writeb(tf->command, ap->ioaddr.command_addr); - rb500_pata_finish_io(ap); + rb532_pata_finish_io(ap); } -static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, +static void rb532_pata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { struct ata_port *ap = adev->link->ap; @@ -84,27 +84,27 @@ static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, *buf = readb(ioaddr); } - rb500_pata_finish_io(adev->link->ap); + rb532_pata_finish_io(adev->link->ap); } -static void rb500_pata_freeze(struct ata_port *ap) +static void rb532_pata_freeze(struct ata_port *ap) { - struct rb500_cf_info *info = ap->host->private_data; + struct rb532_cf_info *info = ap->host->private_data; info->frozen = 1; } -static void rb500_pata_thaw(struct ata_port *ap) +static void rb532_pata_thaw(struct ata_port *ap) { - struct rb500_cf_info *info = ap->host->private_data; + struct rb532_cf_info *info = ap->host->private_data; info->frozen = 0; } -static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) +static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance) { struct ata_host *ah = dev_instance; - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; if (gpio_get_value(info->gpio_line)) { set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); @@ -117,30 +117,30 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) return IRQ_HANDLED; } -static struct ata_port_operations rb500_pata_port_ops = { +static struct ata_port_operations rb532_pata_port_ops = { .inherits = &ata_sff_port_ops, - .sff_exec_command = rb500_pata_exec_command, - .sff_data_xfer = rb500_pata_data_xfer, - .freeze = rb500_pata_freeze, - .thaw = rb500_pata_thaw, + .sff_exec_command = rb532_pata_exec_command, + .sff_data_xfer = rb532_pata_data_xfer, + .freeze = rb532_pata_freeze, + .thaw = rb532_pata_thaw, }; /* ------------------------------------------------------------------------ */ -static struct scsi_host_template rb500_pata_sht = { +static struct scsi_host_template rb532_pata_sht = { ATA_PIO_SHT(DRV_NAME), }; /* ------------------------------------------------------------------------ */ -static void rb500_pata_setup_ports(struct ata_host *ah) +static void rb532_pata_setup_ports(struct ata_host *ah) { - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; struct ata_port *ap; ap = ah->ports[0]; - ap->ops = &rb500_pata_port_ops; + ap->ops = &rb532_pata_port_ops; ap->pio_mask = 0x1f; /* PIO4 */ ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO; @@ -153,13 +153,13 @@ static void rb500_pata_setup_ports(struct ata_host *ah) ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA; } -static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) +static __devinit int rb532_pata_driver_probe(struct platform_device *pdev) { unsigned int irq; int gpio; struct resource *res; struct ata_host *ah; - struct rb500_cf_info *info; + struct rb532_cf_info *info; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -213,10 +213,10 @@ static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) goto err_free_gpio; } - rb500_pata_setup_ports(ah); + rb532_pata_setup_ports(ah); - ret = ata_host_activate(ah, irq, rb500_pata_irq_handler, - IRQF_TRIGGER_LOW, &rb500_pata_sht); + ret = ata_host_activate(ah, irq, rb532_pata_irq_handler, + IRQF_TRIGGER_LOW, &rb532_pata_sht); if (ret) goto err_free_gpio; @@ -228,10 +228,10 @@ err_free_gpio: return ret; } -static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) +static __devexit int rb532_pata_driver_remove(struct platform_device *pdev) { struct ata_host *ah = platform_get_drvdata(pdev); - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; ata_host_detach(ah); gpio_free(info->gpio_line); @@ -242,9 +242,9 @@ static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:" DRV_NAME); -static struct platform_driver rb500_pata_platform_driver = { - .probe = rb500_pata_driver_probe, - .remove = __devexit_p(rb500_pata_driver_remove), +static struct platform_driver rb532_pata_platform_driver = { + .probe = rb532_pata_driver_probe, + .remove = __devexit_p(rb532_pata_driver_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE, @@ -255,16 +255,16 @@ static struct platform_driver rb500_pata_platform_driver = { #define DRV_INFO DRV_DESC " version " DRV_VERSION -static int __init rb500_pata_module_init(void) +static int __init rb532_pata_module_init(void) { printk(KERN_INFO DRV_INFO "\n"); - return platform_driver_register(&rb500_pata_platform_driver); + return platform_driver_register(&rb532_pata_platform_driver); } -static void __exit rb500_pata_module_exit(void) +static void __exit rb532_pata_module_exit(void) { - platform_driver_unregister(&rb500_pata_platform_driver); + platform_driver_unregister(&rb532_pata_platform_driver); } MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); @@ -273,5 +273,5 @@ MODULE_DESCRIPTION(DRV_DESC); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); -module_init(rb500_pata_module_init); -module_exit(rb500_pata_module_exit); +module_init(rb532_pata_module_init); +module_exit(rb532_pata_module_exit); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index d4840748fb5c..2fea6cbe7755 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -464,11 +464,12 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } pci_dev_put(isa); - /* 0x40 low bits indicate enabled channels */ - pci_read_config_byte(pdev, 0x40 , &enable); - enable &= 3; - if (enable == 0) { - return -ENODEV; + if (!(config->flags & VIA_NO_ENABLES)) { + /* 0x40 low bits indicate enabled channels */ + pci_read_config_byte(pdev, 0x40 , &enable); + enable &= 3; + if (enable == 0) + return -ENODEV; } /* Initialise the FIFO for the enabled channels. */ diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index fddd346b1d57..853559e32315 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -678,7 +678,7 @@ static unsigned int sata_fsl_dev_classify(struct ata_port *ap) return ata_dev_classify(&tf); } -static int sata_fsl_prereset(struct ata_linke *link, unsigned long deadline) +static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline) { /* FIXME: Never skip softreset, sata_fsl_softreset() is * combination of soft and hard resets. sata_fsl_softreset() diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 26a6337195b3..842b1a15b78c 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -172,10 +172,11 @@ enum { PCIE_IRQ_MASK_OFS = 0x1910, PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */ - HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, - HC_MAIN_IRQ_MASK_OFS = 0x1d64, - HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020, - HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024, + /* Host Controller Main Interrupt Cause/Mask registers (1 per-chip) */ + PCI_HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, + PCI_HC_MAIN_IRQ_MASK_OFS = 0x1d64, + SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020, + SOC_HC_MAIN_IRQ_MASK_OFS = 0x20024, ERR_IRQ = (1 << 0), /* shift by port # */ DONE_IRQ = (1 << 1), /* shift by port # */ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */ @@ -445,8 +446,8 @@ struct mv_host_priv { const struct mv_hw_ops *ops; int n_ports; void __iomem *base; - void __iomem *main_cause_reg_addr; - void __iomem *main_mask_reg_addr; + void __iomem *main_irq_cause_addr; + void __iomem *main_irq_mask_addr; u32 irq_cause_ofs; u32 irq_mask_ofs; u32 unmask_all_irqs; @@ -727,8 +728,8 @@ static inline unsigned int mv_hardport_from_port(unsigned int port) * Simple code, with two return values, so macro rather than inline. * * port is the sole input, in range 0..7. - * shift is one output, for use with the main_cause and main_mask registers. - * hardport is the other output, in range 0..3 + * shift is one output, for use with main_irq_cause / main_irq_mask registers. + * hardport is the other output, in range 0..3. * * Note that port and hardport may be the same variable in some cases. */ @@ -1679,12 +1680,12 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp /** * mv_host_intr - Handle all interrupts on the given host controller * @host: host specific structure - * @main_cause: Main interrupt cause register for the chip. + * @main_irq_cause: Main interrupt cause register for the chip. * * LOCKING: * Inherited from caller. */ -static int mv_host_intr(struct ata_host *host, u32 main_cause) +static int mv_host_intr(struct ata_host *host, u32 main_irq_cause) { struct mv_host_priv *hpriv = host->private_data; void __iomem *mmio = hpriv->base, *hc_mmio = NULL; @@ -1705,7 +1706,7 @@ static int mv_host_intr(struct ata_host *host, u32 main_cause) * Do nothing if port is not interrupting or is disabled: */ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); - port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ); + port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ); if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED)) continue; /* @@ -1811,20 +1812,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; struct mv_host_priv *hpriv = host->private_data; unsigned int handled = 0; - u32 main_cause, main_mask; + u32 main_irq_cause, main_irq_mask; spin_lock(&host->lock); - main_cause = readl(hpriv->main_cause_reg_addr); - main_mask = readl(hpriv->main_mask_reg_addr); + main_irq_cause = readl(hpriv->main_irq_cause_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); /* * Deal with cases where we either have nothing pending, or have read * a bogus register value which can indicate HW removal or PCI fault. */ - if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) { - if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host))) + if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) { + if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host))) handled = mv_pci_error(host, hpriv->base); else - handled = mv_host_intr(host, main_cause); + handled = mv_host_intr(host, main_irq_cause); } spin_unlock(&host->lock); return IRQ_RETVAL(handled); @@ -2027,7 +2028,7 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio) ZERO(MV_PCI_DISC_TIMER); ZERO(MV_PCI_MSI_TRIGGER); writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); - ZERO(HC_MAIN_IRQ_MASK_OFS); + ZERO(PCI_HC_MAIN_IRQ_MASK_OFS); ZERO(MV_PCI_SERR_MASK); ZERO(hpriv->irq_cause_ofs); ZERO(hpriv->irq_mask_ofs); @@ -2404,7 +2405,7 @@ static void mv_eh_freeze(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; unsigned int shift, hardport, port = ap->port_no; - u32 main_mask; + u32 main_irq_mask; /* FIXME: handle coalescing completion events properly */ @@ -2412,9 +2413,9 @@ static void mv_eh_freeze(struct ata_port *ap) MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); /* disable assertion of portN err, done events */ - main_mask = readl(hpriv->main_mask_reg_addr); - main_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_mask, hpriv->main_mask_reg_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); + main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); + writelfl(main_irq_mask, hpriv->main_irq_mask_addr); } static void mv_eh_thaw(struct ata_port *ap) @@ -2423,7 +2424,7 @@ static void mv_eh_thaw(struct ata_port *ap) unsigned int shift, hardport, port = ap->port_no; void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port); void __iomem *port_mmio = mv_ap_base(ap); - u32 main_mask, hc_irq_cause; + u32 main_irq_mask, hc_irq_cause; /* FIXME: handle coalescing completion events properly */ @@ -2438,9 +2439,9 @@ static void mv_eh_thaw(struct ata_port *ap) writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); /* enable assertion of portN err, done events */ - main_mask = readl(hpriv->main_mask_reg_addr); - main_mask |= ((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_mask, hpriv->main_mask_reg_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); + main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift); + writelfl(main_irq_mask, hpriv->main_irq_mask_addr); } /** @@ -2654,15 +2655,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) goto done; if (HAS_PCI(host)) { - hpriv->main_cause_reg_addr = mmio + HC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_mask_reg_addr = mmio + HC_MAIN_IRQ_MASK_OFS; + hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS; } else { - hpriv->main_cause_reg_addr = mmio + HC_SOC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_mask_reg_addr = mmio + HC_SOC_MAIN_IRQ_MASK_OFS; + hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS; } /* global interrupt mask: 0 == mask everything */ - writel(0, hpriv->main_mask_reg_addr); + writel(0, hpriv->main_irq_mask_addr); n_hc = mv_get_hc_count(host->ports[0]->flags); @@ -2712,23 +2713,23 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); if (IS_GEN_I(hpriv)) writelfl(~HC_MAIN_MASKED_IRQS_5, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); else writelfl(~HC_MAIN_MASKED_IRQS, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_cause_reg_addr), - readl(hpriv->main_mask_reg_addr), + readl(hpriv->main_irq_cause_addr), + readl(hpriv->main_irq_mask_addr), readl(mmio + hpriv->irq_cause_ofs), readl(mmio + hpriv->irq_mask_ofs)); } else { writelfl(~HC_MAIN_MASKED_IRQS_SOC, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_cause_reg_addr), - readl(hpriv->main_mask_reg_addr)); + readl(hpriv->main_irq_cause_addr), + readl(hpriv->main_irq_mask_addr)); } done: return rc; diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 5aa12b011a9a..6adb72a2f876 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 ff2a303cbe00..df55fa8387dc 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/atm/nicstar.c b/drivers/atm/nicstar.c index 38c769f8d2b7..3da804b1627d 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -415,7 +415,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) card->pcidev = pcidev; membase = pci_resource_start(pcidev, 1); card->membase = ioremap(membase, NS_IOREMAP_SIZE); - if (card->membase == 0) + if (!card->membase) { printk("nicstar%d: can't ioremap() membase.\n",i); error = 3; diff --git a/drivers/base/base.h b/drivers/base/base.h index c0444146c09a..2c9ae43e2219 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -64,17 +64,6 @@ extern void sysdev_shutdown(void); extern int sysdev_suspend(pm_message_t state); extern int sysdev_resume(void); -static inline struct class_device *to_class_dev(struct kobject *obj) -{ - return container_of(obj, struct class_device, kobj); -} - -static inline -struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) -{ - return container_of(_attr, struct class_device_attribute, attr); -} - extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index b4901799308b..0ef00e8d4153 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -179,27 +179,13 @@ static void class_create_release(struct class *cls) kfree(cls); } -static void class_device_create_release(struct class_device *class_dev) -{ - pr_debug("%s called for %s\n", __func__, class_dev->class_id); - kfree(class_dev); -} - -/* needed to allow these devices to have parent class devices */ -static int class_device_create_uevent(struct class_device *class_dev, - struct kobj_uevent_env *env) -{ - pr_debug("%s called for %s\n", __func__, class_dev->class_id); - return 0; -} - /** * class_create - create a struct class structure * @owner: pointer to the module that is to "own" this struct class * @name: pointer to a string for the name of this class. * * This is used to create a struct class pointer that can then be used - * in calls to class_device_create(). + * in calls to device_create(). * * Note, the pointer created here is to be destroyed when finished by * making a call to class_destroy(). @@ -218,7 +204,6 @@ struct class *class_create(struct module *owner, const char *name) cls->name = name; cls->owner = owner; cls->class_release = class_create_release; - cls->release = class_device_create_release; retval = class_register(cls); if (retval) @@ -246,113 +231,6 @@ void class_destroy(struct class *cls) class_unregister(cls); } -/* Class Device Stuff */ - -int class_device_create_file(struct class_device *class_dev, - const struct class_device_attribute *attr) -{ - int error = -EINVAL; - if (class_dev) - error = sysfs_create_file(&class_dev->kobj, &attr->attr); - return error; -} - -void class_device_remove_file(struct class_device *class_dev, - const struct class_device_attribute *attr) -{ - if (class_dev) - sysfs_remove_file(&class_dev->kobj, &attr->attr); -} - -int class_device_create_bin_file(struct class_device *class_dev, - struct bin_attribute *attr) -{ - int error = -EINVAL; - if (class_dev) - error = sysfs_create_bin_file(&class_dev->kobj, attr); - return error; -} - -void class_device_remove_bin_file(struct class_device *class_dev, - struct bin_attribute *attr) -{ - if (class_dev) - sysfs_remove_bin_file(&class_dev->kobj, attr); -} - -static ssize_t class_device_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr); - struct class_device *cd = to_class_dev(kobj); - ssize_t ret = 0; - - if (class_dev_attr->show) - ret = class_dev_attr->show(cd, buf); - return ret; -} - -static ssize_t class_device_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t count) -{ - struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr); - struct class_device *cd = to_class_dev(kobj); - ssize_t ret = 0; - - if (class_dev_attr->store) - ret = class_dev_attr->store(cd, buf, count); - return ret; -} - -static struct sysfs_ops class_dev_sysfs_ops = { - .show = class_device_attr_show, - .store = class_device_attr_store, -}; - -static void class_dev_release(struct kobject *kobj) -{ - struct class_device *cd = to_class_dev(kobj); - struct class *cls = cd->class; - - pr_debug("device class '%s': release.\n", cd->class_id); - - if (cd->release) - cd->release(cd); - else if (cls->release) - cls->release(cd); - else { - printk(KERN_ERR "Class Device '%s' does not have a release() " - "function, it is broken and must be fixed.\n", - cd->class_id); - WARN_ON(1); - } -} - -static struct kobj_type class_device_ktype = { - .sysfs_ops = &class_dev_sysfs_ops, - .release = class_dev_release, -}; - -static int class_uevent_filter(struct kset *kset, struct kobject *kobj) -{ - struct kobj_type *ktype = get_ktype(kobj); - - if (ktype == &class_device_ktype) { - struct class_device *class_dev = to_class_dev(kobj); - if (class_dev->class) - return 1; - } - return 0; -} - -static const char *class_uevent_name(struct kset *kset, struct kobject *kobj) -{ - struct class_device *class_dev = to_class_dev(kobj); - - return class_dev->class->name; -} - #ifdef CONFIG_SYSFS_DEPRECATED char *make_class_name(const char *name, struct kobject *kobj) { @@ -370,445 +248,8 @@ char *make_class_name(const char *name, struct kobject *kobj) strcat(class_name, kobject_name(kobj)); return class_name; } - -static int make_deprecated_class_device_links(struct class_device *class_dev) -{ - char *class_name; - int error; - - if (!class_dev->dev) - return 0; - - class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - if (class_name) - error = sysfs_create_link(&class_dev->dev->kobj, - &class_dev->kobj, class_name); - else - error = -ENOMEM; - kfree(class_name); - return error; -} - -static void remove_deprecated_class_device_links(struct class_device *class_dev) -{ - char *class_name; - - if (!class_dev->dev) - return; - - class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - if (class_name) - sysfs_remove_link(&class_dev->dev->kobj, class_name); - kfree(class_name); -} -#else -static inline int make_deprecated_class_device_links(struct class_device *cd) -{ return 0; } -static void remove_deprecated_class_device_links(struct class_device *cd) -{ } #endif -static int class_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) -{ - struct class_device *class_dev = to_class_dev(kobj); - struct device *dev = class_dev->dev; - int retval = 0; - - pr_debug("%s - name = %s\n", __func__, class_dev->class_id); - - if (MAJOR(class_dev->devt)) { - add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); - - add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); - } - - if (dev) { - const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); - if (path) { - add_uevent_var(env, "PHYSDEVPATH=%s", path); - kfree(path); - } - - if (dev->bus) - add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); - - if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", - dev->driver->name); - } - - if (class_dev->uevent) { - /* have the class device specific function add its stuff */ - retval = class_dev->uevent(class_dev, env); - if (retval) - pr_debug("class_dev->uevent() returned %d\n", retval); - } else if (class_dev->class->uevent) { - /* have the class specific function add its stuff */ - retval = class_dev->class->uevent(class_dev, env); - if (retval) - pr_debug("class->uevent() returned %d\n", retval); - } - - return retval; -} - -static struct kset_uevent_ops class_uevent_ops = { - .filter = class_uevent_filter, - .name = class_uevent_name, - .uevent = class_uevent, -}; - -/* - * DO NOT copy how this is created, kset_create_and_add() should be - * called, but this is a hold-over from the old-way and will be deleted - * entirely soon. - */ -static struct kset class_obj_subsys = { - .uevent_ops = &class_uevent_ops, -}; - -static int class_device_add_attrs(struct class_device *cd) -{ - int i; - int error = 0; - struct class *cls = cd->class; - - if (cls->class_dev_attrs) { - for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) { - error = class_device_create_file(cd, - &cls->class_dev_attrs[i]); - if (error) - goto err; - } - } -done: - return error; -err: - while (--i >= 0) - class_device_remove_file(cd, &cls->class_dev_attrs[i]); - goto done; -} - -static void class_device_remove_attrs(struct class_device *cd) -{ - int i; - struct class *cls = cd->class; - - if (cls->class_dev_attrs) { - for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) - class_device_remove_file(cd, &cls->class_dev_attrs[i]); - } -} - -static int class_device_add_groups(struct class_device *cd) -{ - int i; - int error = 0; - - if (cd->groups) { - for (i = 0; cd->groups[i]; i++) { - error = sysfs_create_group(&cd->kobj, cd->groups[i]); - if (error) { - while (--i >= 0) - sysfs_remove_group(&cd->kobj, - cd->groups[i]); - goto out; - } - } - } -out: - return error; -} - -static void class_device_remove_groups(struct class_device *cd) -{ - int i; - if (cd->groups) - for (i = 0; cd->groups[i]; i++) - sysfs_remove_group(&cd->kobj, cd->groups[i]); -} - -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - return print_dev_t(buf, class_dev->devt); -} - -static struct class_device_attribute class_devt_attr = - __ATTR(dev, S_IRUGO, show_dev, NULL); - -static ssize_t store_uevent(struct class_device *class_dev, - const char *buf, size_t count) -{ - kobject_uevent(&class_dev->kobj, KOBJ_ADD); - return count; -} - -static struct class_device_attribute class_uevent_attr = - __ATTR(uevent, S_IWUSR, NULL, store_uevent); - -void class_device_initialize(struct class_device *class_dev) -{ - class_dev->kobj.kset = &class_obj_subsys; - kobject_init(&class_dev->kobj, &class_device_ktype); - INIT_LIST_HEAD(&class_dev->node); -} - -int class_device_add(struct class_device *class_dev) -{ - struct class *parent_class = NULL; - struct class_device *parent_class_dev = NULL; - struct class_interface *class_intf; - int error = -EINVAL; - - class_dev = class_device_get(class_dev); - if (!class_dev) - return -EINVAL; - - if (!strlen(class_dev->class_id)) - goto out1; - - parent_class = class_get(class_dev->class); - if (!parent_class) - goto out1; - - parent_class_dev = class_device_get(class_dev->parent); - - pr_debug("CLASS: registering class device: ID = '%s'\n", - class_dev->class_id); - - /* first, register with generic layer. */ - if (parent_class_dev) - class_dev->kobj.parent = &parent_class_dev->kobj; - else - class_dev->kobj.parent = &parent_class->subsys.kobj; - - error = kobject_add(&class_dev->kobj, class_dev->kobj.parent, - "%s", class_dev->class_id); - if (error) - goto out2; - - /* add the needed attributes to this device */ - error = sysfs_create_link(&class_dev->kobj, - &parent_class->subsys.kobj, "subsystem"); - if (error) - goto out3; - - error = class_device_create_file(class_dev, &class_uevent_attr); - if (error) - goto out3; - - if (MAJOR(class_dev->devt)) { - error = class_device_create_file(class_dev, &class_devt_attr); - if (error) - goto out4; - } - - error = class_device_add_attrs(class_dev); - if (error) - goto out5; - - if (class_dev->dev) { - error = sysfs_create_link(&class_dev->kobj, - &class_dev->dev->kobj, "device"); - if (error) - goto out6; - } - - error = class_device_add_groups(class_dev); - if (error) - goto out7; - - error = make_deprecated_class_device_links(class_dev); - if (error) - goto out8; - - kobject_uevent(&class_dev->kobj, KOBJ_ADD); - - /* notify any interfaces this device is now here */ - down(&parent_class->sem); - list_add_tail(&class_dev->node, &parent_class->children); - list_for_each_entry(class_intf, &parent_class->interfaces, node) { - if (class_intf->add) - class_intf->add(class_dev, class_intf); - } - up(&parent_class->sem); - - goto out1; - - out8: - class_device_remove_groups(class_dev); - out7: - if (class_dev->dev) - sysfs_remove_link(&class_dev->kobj, "device"); - out6: - class_device_remove_attrs(class_dev); - out5: - if (MAJOR(class_dev->devt)) - class_device_remove_file(class_dev, &class_devt_attr); - out4: - class_device_remove_file(class_dev, &class_uevent_attr); - out3: - kobject_del(&class_dev->kobj); - out2: - if (parent_class_dev) - class_device_put(parent_class_dev); - class_put(parent_class); - out1: - class_device_put(class_dev); - return error; -} - -int class_device_register(struct class_device *class_dev) -{ - class_device_initialize(class_dev); - return class_device_add(class_dev); -} - -/** - * class_device_create - creates a class device and registers it with sysfs - * @cls: pointer to the struct class that this device should be registered to. - * @parent: pointer to the parent struct class_device of this new device, if - * any. - * @devt: the dev_t for the char device to be added. - * @device: a pointer to a struct device that is assiociated with this class - * device. - * @fmt: string for the class device's name - * - * This function can be used by char device classes. A struct - * class_device will be created in sysfs, registered to the specified - * class. - * A "dev" file will be created, showing the dev_t for the device, if - * the dev_t is not 0,0. - * If a pointer to a parent struct class_device is passed in, the newly - * created struct class_device will be a child of that device in sysfs. - * The pointer to the struct class_device will be returned from the - * call. Any further sysfs files that might be required can be created - * using this pointer. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). - */ -struct class_device *class_device_create(struct class *cls, - struct class_device *parent, - dev_t devt, - struct device *device, - const char *fmt, ...) -{ - va_list args; - struct class_device *class_dev = NULL; - int retval = -ENODEV; - - if (cls == NULL || IS_ERR(cls)) - goto error; - - class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL); - if (!class_dev) { - retval = -ENOMEM; - goto error; - } - - class_dev->devt = devt; - class_dev->dev = device; - class_dev->class = cls; - class_dev->parent = parent; - class_dev->release = class_device_create_release; - class_dev->uevent = class_device_create_uevent; - - va_start(args, fmt); - vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args); - va_end(args); - retval = class_device_register(class_dev); - if (retval) - goto error; - - return class_dev; - -error: - kfree(class_dev); - return ERR_PTR(retval); -} - -void class_device_del(struct class_device *class_dev) -{ - struct class *parent_class = class_dev->class; - struct class_device *parent_device = class_dev->parent; - struct class_interface *class_intf; - - if (parent_class) { - down(&parent_class->sem); - list_del_init(&class_dev->node); - list_for_each_entry(class_intf, &parent_class->interfaces, node) - if (class_intf->remove) - class_intf->remove(class_dev, class_intf); - up(&parent_class->sem); - } - - if (class_dev->dev) { - remove_deprecated_class_device_links(class_dev); - sysfs_remove_link(&class_dev->kobj, "device"); - } - sysfs_remove_link(&class_dev->kobj, "subsystem"); - class_device_remove_file(class_dev, &class_uevent_attr); - if (MAJOR(class_dev->devt)) - class_device_remove_file(class_dev, &class_devt_attr); - class_device_remove_attrs(class_dev); - class_device_remove_groups(class_dev); - - kobject_uevent(&class_dev->kobj, KOBJ_REMOVE); - kobject_del(&class_dev->kobj); - - class_device_put(parent_device); - class_put(parent_class); -} - -void class_device_unregister(struct class_device *class_dev) -{ - pr_debug("CLASS: Unregistering class device. ID = '%s'\n", - class_dev->class_id); - class_device_del(class_dev); - class_device_put(class_dev); -} - -/** - * class_device_destroy - removes a class device that was created with class_device_create() - * @cls: the pointer to the struct class that this device was registered * with. - * @devt: the dev_t of the device that was previously registered. - * - * This call unregisters and cleans up a class device that was created with a - * call to class_device_create() - */ -void class_device_destroy(struct class *cls, dev_t devt) -{ - struct class_device *class_dev = NULL; - struct class_device *class_dev_tmp; - - down(&cls->sem); - list_for_each_entry(class_dev_tmp, &cls->children, node) { - if (class_dev_tmp->devt == devt) { - class_dev = class_dev_tmp; - break; - } - } - up(&cls->sem); - - if (class_dev) - class_device_unregister(class_dev); -} - -struct class_device *class_device_get(struct class_device *class_dev) -{ - if (class_dev) - return to_class_dev(kobject_get(&class_dev->kobj)); - return NULL; -} - -void class_device_put(struct class_device *class_dev) -{ - if (class_dev) - kobject_put(&class_dev->kobj); -} - /** * class_for_each_device - device iterator * @class: the class we're iterating @@ -897,56 +338,9 @@ struct device *class_find_device(struct class *class, void *data, } EXPORT_SYMBOL_GPL(class_find_device); -/** - * class_find_child - device iterator for locating a particular class_device - * @class: the class we're iterating - * @data: data for the match function - * @match: function to check class_device - * - * This function returns a reference to a class_device that is 'found' for - * later use, as determined by the @match callback. - * - * The callback should return 0 if the class_device doesn't match and non-zero - * if it does. If the callback returns non-zero, this function will - * return to the caller and not iterate over any more class_devices. - * - * Note, you will need to drop the reference with class_device_put() after use. - * - * We hold class->sem in this function, so it can not be - * re-acquired in @match, otherwise it will self-deadlocking. For - * example, calls to add or remove class members would be verboten. - */ -struct class_device *class_find_child(struct class *class, void *data, - int (*match)(struct class_device *, void *)) -{ - struct class_device *dev; - int found = 0; - - if (!class) - return NULL; - - down(&class->sem); - list_for_each_entry(dev, &class->children, node) { - dev = class_device_get(dev); - if (dev) { - if (match(dev, data)) { - found = 1; - break; - } else - class_device_put(dev); - } else - break; - } - up(&class->sem); - - return found ? dev : NULL; -} -EXPORT_SYMBOL_GPL(class_find_child); - int class_interface_register(struct class_interface *class_intf) { struct class *parent; - struct class_device *class_dev; struct device *dev; if (!class_intf || !class_intf->class) @@ -958,10 +352,6 @@ int class_interface_register(struct class_interface *class_intf) down(&parent->sem); list_add_tail(&class_intf->node, &parent->interfaces); - if (class_intf->add) { - list_for_each_entry(class_dev, &parent->children, node) - class_intf->add(class_dev, class_intf); - } if (class_intf->add_dev) { list_for_each_entry(dev, &parent->devices, node) class_intf->add_dev(dev, class_intf); @@ -974,7 +364,6 @@ int class_interface_register(struct class_interface *class_intf) void class_interface_unregister(struct class_interface *class_intf) { struct class *parent = class_intf->class; - struct class_device *class_dev; struct device *dev; if (!parent) @@ -982,10 +371,6 @@ void class_interface_unregister(struct class_interface *class_intf) down(&parent->sem); list_del_init(&class_intf->node); - if (class_intf->remove) { - list_for_each_entry(class_dev, &parent->children, node) - class_intf->remove(class_dev, class_intf); - } if (class_intf->remove_dev) { list_for_each_entry(dev, &parent->devices, node) class_intf->remove_dev(dev, class_intf); @@ -1000,13 +385,6 @@ int __init classes_init(void) class_kset = kset_create_and_add("class", NULL, NULL); if (!class_kset) return -ENOMEM; - - /* ick, this is ugly, the things we go through to keep from showing up - * in sysfs... */ - kset_init(&class_obj_subsys); - kobject_set_name(&class_obj_subsys.kobj, "class_obj"); - if (!class_obj_subsys.kobj.parent) - class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; } @@ -1017,19 +395,5 @@ EXPORT_SYMBOL_GPL(class_unregister); EXPORT_SYMBOL_GPL(class_create); EXPORT_SYMBOL_GPL(class_destroy); -EXPORT_SYMBOL_GPL(class_device_register); -EXPORT_SYMBOL_GPL(class_device_unregister); -EXPORT_SYMBOL_GPL(class_device_initialize); -EXPORT_SYMBOL_GPL(class_device_add); -EXPORT_SYMBOL_GPL(class_device_del); -EXPORT_SYMBOL_GPL(class_device_get); -EXPORT_SYMBOL_GPL(class_device_put); -EXPORT_SYMBOL_GPL(class_device_create); -EXPORT_SYMBOL_GPL(class_device_destroy); -EXPORT_SYMBOL_GPL(class_device_create_file); -EXPORT_SYMBOL_GPL(class_device_remove_file); -EXPORT_SYMBOL_GPL(class_device_create_bin_file); -EXPORT_SYMBOL_GPL(class_device_remove_bin_file); - EXPORT_SYMBOL_GPL(class_interface_register); EXPORT_SYMBOL_GPL(class_interface_unregister); diff --git a/drivers/base/core.c b/drivers/base/core.c index 9248e0927d08..be288b5e4180 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -787,6 +787,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); setup_parent(dev, parent); + /* use parent numa_node */ + if (parent) + set_dev_node(dev, dev_to_node(parent)); + /* first, register with generic layer. */ error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); if (error) @@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent; if (old_parent) klist_remove(&dev->knode_parent); - if (new_parent) + if (new_parent) { klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + set_dev_node(dev, dev_to_node(new_parent)); + } + if (!dev->class) goto out_put; error = device_move_class_links(dev, old_parent, new_parent); @@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent) if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) klist_remove(&dev->knode_parent); - if (old_parent) + dev->parent = old_parent; + if (old_parent) { klist_add_tail(&dev->knode_parent, &old_parent->klist_children); + set_dev_node(dev, dev_to_node(old_parent)); + } } cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 6fe417429977..e38dfed41d80 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -18,7 +18,7 @@ struct sysdev_class cpu_sysdev_class = { }; EXPORT_SYMBOL(cpu_sysdev_class); -static struct sys_device *cpu_sys_devices[NR_CPUS]; +static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices); #ifdef CONFIG_HOTPLUG_CPU static ssize_t show_online(struct sys_device *dev, char *buf) @@ -68,7 +68,7 @@ void unregister_cpu(struct cpu *cpu) sysdev_remove_file(&cpu->sysdev, &attr_online); sysdev_unregister(&cpu->sysdev); - cpu_sys_devices[logical_cpu] = NULL; + per_cpu(cpu_sys_devices, logical_cpu) = NULL; return; } #else /* ... !CONFIG_HOTPLUG_CPU */ @@ -167,7 +167,7 @@ int __cpuinit register_cpu(struct cpu *cpu, int num) if (!error && cpu->hotpluggable) register_cpu_control(cpu); if (!error) - cpu_sys_devices[num] = &cpu->sysdev; + per_cpu(cpu_sys_devices, num) = &cpu->sysdev; if (!error) register_cpu_under_node(num, cpu_to_node(num)); @@ -180,8 +180,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num) struct sys_device *get_cpu_sysdev(unsigned cpu) { - if (cpu < NR_CPUS) - return cpu_sys_devices[cpu]; + if (cpu < nr_cpu_ids && cpu_possible(cpu)) + return per_cpu(cpu_sys_devices, cpu); else return NULL; } diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 9a6537f14401..2ef5acf4368b 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -217,12 +217,22 @@ static void driver_remove_groups(struct device_driver *drv, int driver_register(struct device_driver *drv) { int ret; + struct device_driver *other; if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) printk(KERN_WARNING "Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); + + other = driver_find(drv->name, drv->bus); + if (other) { + put_driver(other); + printk(KERN_ERR "Error: Driver '%s' is already registered, " + "aborting...\n", drv->name); + return -EEXIST; + } + ret = bus_add_driver(drv); if (ret) return ret; diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 1fef7df8c9d6..9fd4a8534146 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -396,6 +396,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (!firmware_p) return -EINVAL; + printk(KERN_INFO "firmware: requesting %s\n", name); + *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", diff --git a/drivers/base/node.c b/drivers/base/node.c index 12fde2d03d69..39f3d1b3a213 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/aoe/aoe.h b/drivers/block/aoe/aoe.h index 280e71ee744c..5b4c6e649c11 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -195,7 +195,6 @@ void aoedev_exit(void); struct aoedev *aoedev_by_aoeaddr(int maj, int min); struct aoedev *aoedev_by_sysminor_m(ulong sysminor); void aoedev_downdev(struct aoedev *d); -int aoedev_isbusy(struct aoedev *d); int aoedev_flush(const char __user *str, size_t size); int aoenet_init(void); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d00293ba3b45..8fc429cf82b6 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -668,16 +668,16 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) u16 n; /* word 83: command set supported */ - n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1])); + n = get_unaligned_le16(&id[83 << 1]); /* word 86: command set/feature enabled */ - n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1])); + n |= get_unaligned_le16(&id[86 << 1]); if (n & (1<<10)) { /* bit 10: LBA 48 */ d->flags |= DEVFL_EXT; /* word 100: number lba48 sectors */ - ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1])); + ssize = get_unaligned_le64(&id[100 << 1]); /* set as in ide-disk.c:init_idedisk_capacity */ d->geo.cylinders = ssize; @@ -688,12 +688,12 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) d->flags &= ~DEVFL_EXT; /* number lba28 sectors */ - ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1])); + ssize = get_unaligned_le32(&id[60 << 1]); /* NOTE: obsolete in ATA 6 */ - d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1])); - d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); - d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); + d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); + d->geo.heads = get_unaligned_le16(&id[55 << 1]); + d->geo.sectors = get_unaligned_le16(&id[56 << 1]); } if (d->ssize != ssize) @@ -779,7 +779,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) u16 aoemajor; hin = (struct aoe_hdr *) skb_mac_header(skb); - aoemajor = be16_to_cpu(get_unaligned(&hin->major)); + aoemajor = get_unaligned_be16(&hin->major); d = aoedev_by_aoeaddr(aoemajor, hin->minor); if (d == NULL) { snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " @@ -791,7 +791,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - n = be32_to_cpu(get_unaligned(&hin->tag)); + n = get_unaligned_be32(&hin->tag); t = gettgt(d, hin->src); if (t == NULL) { printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", @@ -806,9 +806,9 @@ aoecmd_ata_rsp(struct sk_buff *skb) snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", "unexpected rsp", - be16_to_cpu(get_unaligned(&hin->major)), + get_unaligned_be16(&hin->major), hin->minor, - be32_to_cpu(get_unaligned(&hin->tag)), + get_unaligned_be32(&hin->tag), jiffies); aoechr_error(ebuf); return; @@ -873,7 +873,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) printk(KERN_INFO "aoe: unrecognized ata command %2.2Xh for %d.%d\n", ahout->cmdstat, - be16_to_cpu(get_unaligned(&hin->major)), + get_unaligned_be16(&hin->major), hin->minor); } } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index f9a1cd9edb77..a1d813ab0d6b 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -18,24 +18,6 @@ static void skbpoolfree(struct aoedev *d); static struct aoedev *devlist; static DEFINE_SPINLOCK(devlist_lock); -int -aoedev_isbusy(struct aoedev *d) -{ - struct aoetgt **t, **te; - struct frame *f, *e; - - t = d->targets; - te = t + NTARGETS; - for (; t < te && *t; t++) { - f = (*t)->frames; - e = f + (*t)->nframes; - for (; f < e; f++) - if (f->tag != FREETAG) - return 1; - } - return 0; -} - struct aoedev * aoedev_by_aoeaddr(int maj, int min) { diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 18d243c73eee..d625169c8e48 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -128,7 +128,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, skb_push(skb, ETH_HLEN); /* (1) */ h = (struct aoe_hdr *) skb_mac_header(skb); - n = be32_to_cpu(get_unaligned(&h->tag)); + n = get_unaligned_be32(&h->tag); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; @@ -140,7 +140,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, printk(KERN_ERR "%s%d.%d@%s; ecode=%d '%s'\n", "aoe: error packet from ", - be16_to_cpu(get_unaligned(&h->major)), + get_unaligned_be16(&h->major), h->minor, skb->dev->name, h->err, aoe_errlist[n]); goto exit; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 7bd76639544c..a196ef7f147f 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -319,7 +319,7 @@ out: #ifdef CONFIG_BLK_DEV_XIP static int brd_direct_access (struct block_device *bdev, sector_t sector, - unsigned long *data) + void **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; struct page *page; @@ -333,7 +333,8 @@ static int brd_direct_access (struct block_device *bdev, sector_t sector, page = brd_insert_page(brd, sector); if (!page) return -ENOMEM; - *data = (unsigned long)page_address(page); + *kaddr = page_address(page); + *pfn = page_to_pfn(page); return 0; } @@ -386,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); @@ -434,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; @@ -522,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) { @@ -530,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")) @@ -569,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/block/cciss.c b/drivers/block/cciss.c index cf6083a1f928..e336b05fe4a7 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -425,16 +425,12 @@ static void __devinit cciss_procinit(int i) struct proc_dir_entry *pde; if (proc_cciss == NULL) - proc_cciss = proc_mkdir("cciss", proc_root_driver); + proc_cciss = proc_mkdir("driver/cciss", NULL); if (!proc_cciss) return; - pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP | + pde = proc_create_data(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, proc_cciss, - &cciss_proc_fops); - if (!pde) - return; - - pde->data = hba[i]; + &cciss_proc_fops, hba[i]); } #endif /* CONFIG_PROC_FS */ @@ -3700,7 +3696,7 @@ static void __exit cciss_cleanup(void) cciss_remove_one(hba[i]->pdev); } } - remove_proc_entry("cciss", proc_root_driver); + remove_proc_entry("driver/cciss", NULL); } static void fail_all_cmds(unsigned long ctlr) diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 69199185ff4b..09c14341e6e3 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -214,7 +214,7 @@ static struct proc_dir_entry *proc_array; static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = proc_mkdir("cpqarray", proc_root_driver); + proc_array = proc_mkdir("driver/cpqarray", NULL); if (!proc_array) return; } @@ -1796,7 +1796,7 @@ static void __exit cpqarray_exit(void) } } - remove_proc_entry("cpqarray", proc_root_driver); + remove_proc_entry("driver/cpqarray", NULL); } module_init(cpqarray_init) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 7652e87d60c5..395f8ea7981c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4526,14 +4526,15 @@ static void __init parse_floppy_cfg_string(char *cfg) } } -int __init init_module(void) +static int __init floppy_module_init(void) { if (floppy) parse_floppy_cfg_string(floppy); return floppy_init(); } +module_init(floppy_module_init); -void cleanup_module(void) +static void __exit floppy_module_exit(void) { int drive; @@ -4562,6 +4563,7 @@ void cleanup_module(void) /* eject disk, if any */ fd_eject(0); } +module_exit(floppy_module_exit); module_param(floppy, charp, 0); module_param(FLOPPY_IRQ, int, 0); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f7f163557aa0..d3a25b027ff9 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -546,7 +546,7 @@ static void loop_unplug(struct request_queue *q) { struct loop_device *lo = q->queuedata; - clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); + queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q); blk_run_address_space(lo->lo_backing_file->f_mapping); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 60cc54368b66..ad98dda6037d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <net/sock.h> #include <linux/net.h> +#include <linux/kthread.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -55,6 +56,7 @@ static unsigned int debugflags; static unsigned int nbds_max = 16; static struct nbd_device *nbd_dev; +static int max_part; /* * Use just one lock (or at most 1 per NIC). Two arguments for this: @@ -337,7 +339,7 @@ static struct request *nbd_read_stat(struct nbd_device *lo) } req = nbd_find_request(lo, *(struct request **)reply.handle); - if (unlikely(IS_ERR(req))) { + if (IS_ERR(req)) { result = PTR_ERR(req); if (result != -ENOENT) goto harderror; @@ -441,6 +443,85 @@ static void nbd_clear_que(struct nbd_device *lo) } +static void nbd_handle_req(struct nbd_device *lo, struct request *req) +{ + if (!blk_fs_request(req)) + goto error_out; + + nbd_cmd(req) = NBD_CMD_READ; + if (rq_data_dir(req) == WRITE) { + nbd_cmd(req) = NBD_CMD_WRITE; + if (lo->flags & NBD_READ_ONLY) { + printk(KERN_ERR "%s: Write on read-only\n", + lo->disk->disk_name); + goto error_out; + } + } + + req->errors = 0; + + mutex_lock(&lo->tx_lock); + if (unlikely(!lo->sock)) { + mutex_unlock(&lo->tx_lock); + printk(KERN_ERR "%s: Attempted send on closed socket\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + return; + } + + lo->active_req = req; + + if (nbd_send_req(lo, req) != 0) { + printk(KERN_ERR "%s: Request send failed\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + } else { + spin_lock(&lo->queue_lock); + list_add(&req->queuelist, &lo->queue_head); + spin_unlock(&lo->queue_lock); + } + + lo->active_req = NULL; + mutex_unlock(&lo->tx_lock); + wake_up_all(&lo->active_wq); + + return; + +error_out: + req->errors++; + nbd_end_request(req); +} + +static int nbd_thread(void *data) +{ + struct nbd_device *lo = data; + struct request *req; + + set_user_nice(current, -20); + while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) { + /* wait for something to do */ + wait_event_interruptible(lo->waiting_wq, + kthread_should_stop() || + !list_empty(&lo->waiting_queue)); + + /* extract request */ + if (list_empty(&lo->waiting_queue)) + continue; + + spin_lock_irq(&lo->queue_lock); + req = list_entry(lo->waiting_queue.next, struct request, + queuelist); + list_del_init(&req->queuelist); + spin_unlock_irq(&lo->queue_lock); + + /* handle request */ + nbd_handle_req(lo, req); + } + return 0; +} + /* * We always wait for result of write, for now. It would be nice to make it optional * in future @@ -456,65 +537,23 @@ static void do_nbd_request(struct request_queue * q) struct nbd_device *lo; blkdev_dequeue_request(req); + + spin_unlock_irq(q->queue_lock); + dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", req->rq_disk->disk_name, req, req->cmd_type); - if (!blk_fs_request(req)) - goto error_out; - lo = req->rq_disk->private_data; BUG_ON(lo->magic != LO_MAGIC); - nbd_cmd(req) = NBD_CMD_READ; - if (rq_data_dir(req) == WRITE) { - nbd_cmd(req) = NBD_CMD_WRITE; - if (lo->flags & NBD_READ_ONLY) { - printk(KERN_ERR "%s: Write on read-only\n", - lo->disk->disk_name); - goto error_out; - } - } - - req->errors = 0; - spin_unlock_irq(q->queue_lock); - - mutex_lock(&lo->tx_lock); - if (unlikely(!lo->sock)) { - mutex_unlock(&lo->tx_lock); - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - spin_lock_irq(q->queue_lock); - continue; - } - - lo->active_req = req; + spin_lock_irq(&lo->queue_lock); + list_add_tail(&req->queuelist, &lo->waiting_queue); + spin_unlock_irq(&lo->queue_lock); - if (nbd_send_req(lo, req) != 0) { - printk(KERN_ERR "%s: Request send failed\n", - lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - } else { - spin_lock(&lo->queue_lock); - list_add(&req->queuelist, &lo->queue_head); - spin_unlock(&lo->queue_lock); - } - - lo->active_req = NULL; - mutex_unlock(&lo->tx_lock); - wake_up_all(&lo->active_wq); + wake_up(&lo->waiting_wq); spin_lock_irq(q->queue_lock); - continue; - -error_out: - req->errors++; - spin_unlock(q->queue_lock); - nbd_end_request(req); - spin_lock(q->queue_lock); } } @@ -524,6 +563,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; int error; struct request sreq ; + struct task_struct *thread; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -537,6 +577,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, switch (cmd) { case NBD_DISCONNECT: printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; /* @@ -571,10 +612,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file, error = -EINVAL; file = fget(arg); if (file) { + struct block_device *bdev = inode->i_bdev; inode = file->f_path.dentry->d_inode; if (S_ISSOCK(inode->i_mode)) { lo->file = file; lo->sock = SOCKET_I(inode); + if (max_part > 0) + bdev->bd_invalidated = 1; error = 0; } else { fput(file); @@ -606,7 +650,12 @@ static int nbd_ioctl(struct inode *inode, struct file *file, case NBD_DO_IT: if (!lo->file) return -EINVAL; + thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); + if (IS_ERR(thread)) + return PTR_ERR(thread); + wake_up_process(thread); error = nbd_do_it(lo); + kthread_stop(thread); if (error) return error; sock_shutdown(lo, 1); @@ -619,6 +668,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file, lo->bytesize = 0; inode->i_bdev->bd_inode->i_size = 0; set_capacity(lo->disk, 0); + if (max_part > 0) + ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0); return lo->harderror; case NBD_CLEAR_QUE: /* @@ -652,6 +703,7 @@ static int __init nbd_init(void) { int err = -ENOMEM; int i; + int part_shift; BUILD_BUG_ON(sizeof(struct nbd_request) != 28); @@ -659,8 +711,17 @@ static int __init nbd_init(void) if (!nbd_dev) return -ENOMEM; + if (max_part < 0) { + printk(KERN_CRIT "nbd: max_part must be >= 0\n"); + return -EINVAL; + } + + part_shift = 0; + if (max_part > 0) + part_shift = fls(max_part); + for (i = 0; i < nbds_max; i++) { - struct gendisk *disk = alloc_disk(1); + struct gendisk *disk = alloc_disk(1 << part_shift); elevator_t *old_e; if (!disk) goto out; @@ -695,17 +756,18 @@ static int __init nbd_init(void) nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; + INIT_LIST_HEAD(&nbd_dev[i].waiting_queue); spin_lock_init(&nbd_dev[i].queue_lock); INIT_LIST_HEAD(&nbd_dev[i].queue_head); mutex_init(&nbd_dev[i].tx_lock); init_waitqueue_head(&nbd_dev[i].active_wq); + init_waitqueue_head(&nbd_dev[i].waiting_wq); nbd_dev[i].blksize = 1024; nbd_dev[i].bytesize = 0; disk->major = NBD_MAJOR; - disk->first_minor = i; + disk->first_minor = i << part_shift; disk->fops = &nbd_fops; disk->private_data = &nbd_dev[i]; - disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "nbd%d", i); set_capacity(disk, 0); add_disk(disk); @@ -743,7 +805,9 @@ MODULE_DESCRIPTION("Network Block Device"); MODULE_LICENSE("GPL"); module_param(nbds_max, int, 0444); -MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize."); +MODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)"); +module_param(max_part, int, 0444); +MODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)"); #ifndef NDEBUG module_param(debugflags, int, 0644); MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index df819f8a95a6..570f3b70dce7 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -716,10 +716,8 @@ static int pd_special_command(struct pd_unit *disk, struct request rq; int err = 0; - memset(&rq, 0, sizeof(rq)); - rq.errors = 0; + blk_rq_init(NULL, &rq); rq.rq_disk = disk->gd; - rq.ref_count = 1; rq.end_io_data = &wait; rq.end_io = blk_end_sync_rq; blk_insert_request(disk->gd->queue, &rq, 0, func); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 18feb1c7c33b..3ba1df93e9e3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -776,8 +776,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]); memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); - if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) - memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); rq->timeout = 60*HZ; rq->cmd_type = REQ_TYPE_BLOCK_PC; @@ -2744,7 +2742,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) int i; int ret = 0; char b[BDEVNAME_SIZE]; - struct proc_dir_entry *proc; struct block_device *bdev; if (pd->pkt_dev == dev) { @@ -2788,11 +2785,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) goto out_mem; } - proc = create_proc_entry(pd->name, 0, pkt_proc); - if (proc) { - proc->data = pd; - proc->proc_fops = &pkt_proc_fops; - } + proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd); DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); return 0; @@ -3101,7 +3094,7 @@ static int __init pkt_init(void) goto out_misc; } - pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); + pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL); return 0; @@ -3117,7 +3110,7 @@ out2: static void __exit pkt_exit(void) { - remove_proc_entry(DRIVER_NAME, proc_root_driver); + remove_proc_entry("driver/"DRIVER_NAME, NULL); misc_deregister(&pkt_misc); pkt_debugfs_cleanup(); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 7483f947f0e9..d797e209951d 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -102,8 +102,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), - (unsigned long)iter.bio->bi_sector); + bio_sectors(iter.bio), iter.bio->bi_sector); size = bvec->bv_len; buf = bvec_kmap_irq(bvec, &flags); @@ -406,7 +405,6 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req) dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - memset(req->cmd, 0, sizeof(req->cmd)); req->cmd_type = REQ_TYPE_FLUSH; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 27bfe72aab59..3a281ef11ffa 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -205,6 +205,7 @@ struct ub_scsi_cmd { unsigned char key, asc, ascq; /* May be valid if error==-EIO */ int stat_count; /* Retries getting status. */ + unsigned int timeo; /* jiffies until rq->timeout changes */ unsigned int len; /* Requested length */ unsigned int current_sg; @@ -318,6 +319,7 @@ struct ub_dev { int openc; /* protected by ub_lock! */ /* kref is too implicit for our taste */ int reset; /* Reset is running */ + int bad_resid; unsigned int tagcnt; char name[12]; struct usb_device *dev; @@ -764,6 +766,12 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, cmd->cdb_len = rq->cmd_len; cmd->len = rq->data_len; + + /* + * To reapply this to every URB is not as incorrect as it looks. + * In return, we avoid any complicated tracking calculations. + */ + cmd->timeo = rq->timeout; } static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) @@ -785,10 +793,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) scsi_status = 0; } else { if (cmd->act_len != cmd->len) { - if ((cmd->key == MEDIUM_ERROR || - cmd->key == UNIT_ATTENTION) && - ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) - return; scsi_status = SAM_STAT_CHECK_CONDITION; } else { scsi_status = 0; @@ -804,7 +808,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) else scsi_status = DID_ERROR << 16; } else { - if (cmd->error == -EIO) { + if (cmd->error == -EIO && + (cmd->key == 0 || + cmd->key == MEDIUM_ERROR || + cmd->key == UNIT_ATTENTION)) { if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) return; } @@ -1259,14 +1266,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } - len = le32_to_cpu(bcs->Residue); - if (len != cmd->len - cmd->act_len) { - /* - * It is all right to transfer less, the caller has - * to check. But it's not all right if the device - * counts disagree with our counts. - */ - goto Bad_End; + if (!sc->bad_resid) { + len = le32_to_cpu(bcs->Residue); + if (len != cmd->len - cmd->act_len) { + /* + * Only start ignoring if this cmd ended well. + */ + if (cmd->len == cmd->act_len) { + printk(KERN_NOTICE "%s: " + "bad residual %d of %d, ignoring\n", + sc->name, len, cmd->len); + sc->bad_resid = 1; + } + } } switch (bcs->Status) { @@ -1297,8 +1309,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ub_state_done(sc, cmd, -EIO); } else { - printk(KERN_WARNING "%s: " - "wrong command state %d\n", + printk(KERN_WARNING "%s: wrong command state %d\n", sc->name, cmd->state); ub_state_done(sc, cmd, -EINVAL); return; @@ -1336,7 +1347,10 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } - sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT; + if (cmd->timeo) + sc->work_timer.expires = jiffies + cmd->timeo; + else + sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT; add_timer(&sc->work_timer); cmd->state = UB_CMDST_DATA; @@ -1376,7 +1390,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return -1; } - sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; + if (cmd->timeo) + sc->work_timer.expires = jiffies + cmd->timeo; + else + sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; add_timer(&sc->work_timer); return 0; } @@ -1515,8 +1532,7 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) return; } if (cmd->state != UB_CMDST_SENSE) { - printk(KERN_WARNING "%s: " - "sense done with bad cmd state %d\n", + printk(KERN_WARNING "%s: sense done with bad cmd state %d\n", sc->name, cmd->state); return; } @@ -1720,7 +1736,7 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp, } /* - * This is called once a new disk was seen by the block layer or by ub_probe(). + * This is called by check_disk_change if we reported a media change. * The main onjective here is to discover the features of the media such as * the capacity, read-only status, etc. USB storage generally does not * need to be spun up, but if we needed it, this would be the place. @@ -2136,8 +2152,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, } if (ep_in == NULL || ep_out == NULL) { - printk(KERN_NOTICE "%s: failed endpoint check\n", - sc->name); + printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name); return -ENODEV; } @@ -2354,7 +2369,7 @@ static void ub_disconnect(struct usb_interface *intf) spin_unlock_irqrestore(&ub_lock, flags); /* - * Fence stall clearnings, operations triggered by unlinkings and so on. + * Fence stall clearings, operations triggered by unlinkings and so on. * We do not attempt to unlink any URBs, because we do not trust the * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. */ @@ -2399,7 +2414,7 @@ static void ub_disconnect(struct usb_interface *intf) del_gendisk(lun->disk); /* * I wish I could do: - * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags); + * queue_flag_set(QUEUE_FLAG_DEAD, q); * As it is, we rely on our internal poisoning and let * the upper levels to spin furiously failing all the I/O. */ @@ -2417,7 +2432,7 @@ static void ub_disconnect(struct usb_interface *intf) spin_unlock_irqrestore(sc->lock, flags); /* - * There is virtually no chance that other CPU runs times so long + * There is virtually no chance that other CPU runs a timeout so long * after ub_urb_complete should have called del_timer, but only if HCD * didn't forget to deliver a callback on unlink. */ diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 0cfbe8c594a5..84e064ffee52 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -35,7 +35,7 @@ struct virtblk_req struct list_head list; struct request *req; struct virtio_blk_outhdr out_hdr; - struct virtio_blk_inhdr in_hdr; + u8 status; }; static void blk_done(struct virtqueue *vq) @@ -48,7 +48,7 @@ static void blk_done(struct virtqueue *vq) spin_lock_irqsave(&vblk->lock, flags); while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { int uptodate; - switch (vbr->in_hdr.status) { + switch (vbr->status) { case VIRTIO_BLK_S_OK: uptodate = 1; break; @@ -101,7 +101,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, sg_init_table(vblk->sg, VIRTIO_MAX_SG); sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr)); num = blk_rq_map_sg(q, vbr->req, vblk->sg+1); - sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr)); + sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status)); if (rq_data_dir(vbr->req) == WRITE) { vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; @@ -157,10 +157,25 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp, /* We provide getgeo only to please some old bootloader/partitioning tools */ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) { - /* some standard values, similar to sd */ - geo->heads = 1 << 6; - geo->sectors = 1 << 5; - geo->cylinders = get_capacity(bd->bd_disk) >> 11; + struct virtio_blk *vblk = bd->bd_disk->private_data; + struct virtio_blk_geometry vgeo; + int err; + + /* see if the host passed in geometry config */ + err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY, + offsetof(struct virtio_blk_config, geometry), + &vgeo); + + if (!err) { + geo->heads = vgeo.heads; + geo->sectors = vgeo.sectors; + geo->cylinders = vgeo.cylinders; + } else { + /* some standard values, similar to sd */ + geo->heads = 1 << 6; + geo->sectors = 1 << 5; + geo->cylinders = get_capacity(bd->bd_disk) >> 11; + } return 0; } @@ -242,12 +257,12 @@ static int virtblk_probe(struct virtio_device *vdev) index++; /* If barriers are supported, tell block layer that queue is ordered */ - if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER)) + if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); /* Host must always specify the capacity. */ - __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity), - &cap); + vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), + &cap, sizeof(cap)); /* If capacity is too big, truncate with warning. */ if ((sector_t)cap != cap) { @@ -289,7 +304,6 @@ out: static void virtblk_remove(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; - int major = vblk->disk->major; /* Nothing should be pending. */ BUG_ON(!list_empty(&vblk->reqs)); @@ -299,7 +313,6 @@ static void virtblk_remove(struct virtio_device *vdev) blk_cleanup_queue(vblk->disk->queue); put_disk(vblk->disk); - unregister_blkdev(major, "virtblk"); mempool_destroy(vblk->pool); vdev->config->del_vq(vblk->vq); kfree(vblk); @@ -310,7 +323,14 @@ static struct virtio_device_id id_table[] = { { 0 }, }; +static unsigned int features[] = { + VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, + VIRTIO_BLK_F_GEOMETRY, +}; + static struct virtio_driver virtio_blk = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index d771da816d95..f2fff5799ddf 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -137,7 +137,7 @@ static void blkif_restart_queue_callback(void *arg) schedule_work(&info->work); } -int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) +static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) { /* We don't have real geometry info, but let's at least return values consistent with the size of the device */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 7e31d5f1bc8a..e5cd856a2fea 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/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index ac3829030ac5..69f26eb6415b 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2194,7 +2194,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, if (ret) break; - memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_READ_CD; rq->cmd[1] = 1 << 2; rq->cmd[2] = (lba >> 24) & 0xff; diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index b74b6c2768a8..5245a4a0ba74 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -144,6 +144,7 @@ static int proc_viocd_open(struct inode *inode, struct file *file) } static const struct file_operations proc_viocd_operations = { + .owner = THIS_MODULE, .open = proc_viocd_open, .read = seq_read, .llseek = seq_lseek, @@ -679,7 +680,6 @@ static struct vio_driver viocd_driver = { static int __init viocd_init(void) { - struct proc_dir_entry *e; int ret = 0; if (!firmware_has_feature(FW_FEATURE_ISERIES)) @@ -719,12 +719,8 @@ static int __init viocd_init(void) if (ret) goto out_free_info; - e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viocd_operations; - } - + proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, + &proc_viocd_operations); return 0; out_free_info: diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2906ee7bd298..5dce3877eee5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -80,6 +80,15 @@ config VT_HW_CONSOLE_BINDING information. For framebuffer console users, please refer to <file:Documentation/fb/fbcon.txt>. +config DEVKMEM + bool "/dev/kmem virtual device support" + default y + help + Say Y here if you want to support the /dev/kmem device. The + /dev/kmem device is rarely used, but can be used for certain + kind of kernel debugging operations. + When in doubt, say "N". + config SERIAL_NONSTANDARD bool "Non-standard serial port support" depends on HAS_IOMEM @@ -732,9 +741,16 @@ config NVRAM To compile this driver as a module, choose M here: the module will be called nvram. +# +# These legacy RTC drivers just cause too many conflicts with the generic +# RTC framework ... let's not even try to coexist any more. +# +if RTC_LIB=n + config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32 + depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \ + && !ARM && !SUPERH && !S390 && !AVR32 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -840,6 +856,8 @@ config DS1302 will get access to the real time clock (or hardware clock) built into your computer. +endif # RTC_LIB + config COBALT_LCD bool "Support for Cobalt LCD" depends on MIPS_COBALT diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index c69f79598e47..99e6a406efb4 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 3d468f502d2d..37457e5a4f2b 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/apm-emulation.c b/drivers/char/apm-emulation.c index 17d54315e146..cdd876dbb2b0 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -14,6 +14,7 @@ #include <linux/poll.h> #include <linux/slab.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/miscdevice.h> #include <linux/apm_bios.h> #include <linux/capability.h> @@ -493,11 +494,10 @@ static struct miscdevice apm_device = { * -1: Unknown * 8) min = minutes; sec = seconds */ -static int apm_get_info(char *buf, char **start, off_t fpos, int length) +static int proc_apm_show(struct seq_file *m, void *v) { struct apm_power_info info; char *units; - int ret; info.ac_line_status = 0xff; info.battery_status = 0xff; @@ -515,14 +515,27 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) case 1: units = "sec"; break; } - ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", driver_version, APM_32_BIT_SUPPORT, info.ac_line_status, info.battery_status, info.battery_flag, info.battery_life, info.time, units); - return ret; + return 0; } + +static int proc_apm_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_apm_show, NULL); +} + +static const struct file_operations apm_proc_fops = { + .owner = THIS_MODULE, + .open = proc_apm_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif static int kapmd(void *arg) @@ -593,7 +606,7 @@ static int __init apm_init(void) wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS - create_proc_info_entry("apm", 0, NULL, apm_get_info); + proc_create("apm", 0, NULL, &apm_proc_fops); #endif ret = misc_register(&apm_device); diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index a7c4990b5b6b..31d08b641f5b 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 6b104e45a322..4246b8e36cb3 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/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index c2d23cae9515..c0a4a0bb509e 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -215,7 +215,7 @@ static int __init cs5535_gpio_init(void) else mask = 0x0b003c66; - if (request_region(gpio_base, CS5535_GPIO_SIZE, NAME) == 0) { + if (!request_region(gpio_base, CS5535_GPIO_SIZE, NAME)) { printk(KERN_ERR NAME ": can't allocate I/O for GPIO\n"); return -ENODEV; } diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e4f579c3e245..ef73e72daedc 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 ecee3547a13f..213b3ca3468e 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 7a1d9a782ddb..9a32169e88fb 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 60c9376be486..a86ab30b4620 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 4caba8c54455..b5bf8cc0fdaa 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 a33db5f0967f..91ec2bb497e9 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 ef7bf143a80c..f47e46e3529f 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 c614d78b3dfd..db7001f22561 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/r128_cce.c b/drivers/char/drm/r128_cce.c index f36adbd3aaf5..c31afbde62e7 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -817,7 +817,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev) for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if (buf->file_priv == 0) + if (!buf->file_priv) return buf; } diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 9072e4a1894e..f6f6c92bf771 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 59146e3365ba..ea35ab2c9909 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 ffd747c5dff0..60a4df7dac12 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 f3fe62067344..84840ba13ff0 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 7ed7da1d99cf..252f73e48596 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 1399971be689..e7fb0bca3667 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 d5a752da322f..59c6f9ab94e4 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/i8k.c b/drivers/char/i8k.c index 8609b8236c67..b60d425ce8d1 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -77,11 +77,16 @@ static int power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); +static int fan_mult = I8K_FAN_MULT; +module_param(fan_mult, int, 0); +MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); + static int i8k_open_fs(struct inode *inode, struct file *file); static int i8k_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static const struct file_operations i8k_fops = { + .owner = THIS_MODULE, .open = i8k_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -238,7 +243,7 @@ static int i8k_get_fan_speed(int fan) struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; regs.ebx = fan & 0xff; - return i8k_smm(®s) ? : (regs.eax & 0xffff) * I8K_FAN_MULT; + return i8k_smm(®s) ? : (regs.eax & 0xffff) * fan_mult; } /* @@ -554,13 +559,10 @@ static int __init i8k_init(void) return -ENODEV; /* Register the proc entry */ - proc_i8k = create_proc_entry("i8k", 0, NULL); + proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops); if (!proc_i8k) return -ENOENT; - proc_i8k->proc_fops = &i8k_fops; - proc_i8k->owner = THIS_MODULE; - printk(KERN_INFO "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", I8K_VERSION); diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c index 61ef013b8445..3601017f58cf 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 433305062fb8..c88a64e527aa 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 15fe04e748f4..8aa6e7ab8d5b 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 9c25320121ef..938879cc7bcc 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 eff9b542d699..000000000000 --- 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 b1d6cad84282..70957acaa960 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -133,8 +133,9 @@ *****************/ #include <linux/proc_fs.h> +#include <linux/seq_file.h> -static int ip2_read_procmem(char *, char **, off_t, int); +static const struct file_operations ip2mem_proc_fops; static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************/ @@ -168,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); @@ -354,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 */ /******************************************************************************/ @@ -380,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; @@ -423,7 +425,7 @@ cleanup_module(void) } put_tty_driver(ip2_tty_driver); unregister_chrdev(IP2_IPL_MAJOR, pcIpl); - remove_proc_entry("ip2mem", &proc_root); + remove_proc_entry("ip2mem", NULL); // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { @@ -451,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 = { @@ -695,7 +698,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } } /* Register the read_procmem thing */ - if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) { + if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { printk(KERN_ERR "IP2: failed to register read_procmem\n"); } else { @@ -1049,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; @@ -1069,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; @@ -1086,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); @@ -1267,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 ); @@ -1613,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; @@ -1716,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 ); @@ -1735,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; @@ -1743,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 ); } @@ -1769,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 ); @@ -1783,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); } /******************************************************************************/ @@ -1801,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 ); @@ -1833,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; } @@ -1862,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); @@ -1950,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 @@ -2201,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); @@ -2223,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 */ @@ -2263,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); @@ -2871,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; @@ -2967,65 +2969,61 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile ) } return 0; } -/******************************************************************************/ -/* Function: ip2_read_procmem */ -/* Parameters: */ -/* */ -/* Returns: Length of output */ -/* */ -/* Description: */ -/* Supplies some driver operating parameters */ -/* Not real useful unless your debugging the fifo */ -/* */ -/******************************************************************************/ - -#define LIMIT (PAGE_SIZE - 120) static int -ip2_read_procmem(char *buf, char **start, off_t offset, int len) +proc_ip2mem_show(struct seq_file *m, void *v) { i2eBordStrPtr pB; i2ChanStrPtr pCh; PTTY tty; int i; - len = 0; - #define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n" #define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n" #define FMTLIN3 " 0x%04x 0x%04x rc flow\n" - len += sprintf(buf+len,"\n"); + seq_printf(m,"\n"); for( i = 0; i < IP2_MAX_BOARDS; ++i ) { pB = i2BoardPtrTable[i]; if ( pB ) { - len += sprintf(buf+len,"board %d:\n",i); - len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n", + seq_printf(m,"board %d:\n",i); + seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n", pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting); } } - len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n"); + seq_printf(m,"#: tty flags, port flags, cflags, iflags\n"); for (i=0; i < IP2_MAX_PORTS; i++) { - if (len > LIMIT) - break; pCh = DevTable[i]; if (pCh) { tty = pCh->pTTY; if (tty && tty->count) { - len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags, + seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags, tty->termios->c_cflag,tty->termios->c_iflag); - len += sprintf(buf+len,FMTLIN2, + seq_printf(m,FMTLIN2, pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds); - len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room); + seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room); } } } - return len; + return 0; +} + +static int proc_ip2mem_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_ip2mem_show, NULL); } +static const struct file_operations ip2mem_proc_fops = { + .owner = THIS_MODULE, + .open = proc_ip2mem_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * This is the handler for /proc/tty/driver/ip2 * diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 553f0a408eda..eb8a1a8c188e 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -9,7 +9,3 @@ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o - -ipmi_si.o: $(ipmi_si-objs) - $(LD) -r -o $@ $(ipmi_si-objs) - diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index e736119b6497..7b98c067190a 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -37,26 +37,32 @@ #define BT_DEBUG_ENABLE 1 /* Generic messages */ #define BT_DEBUG_MSG 2 /* Prints all request/response buffers */ #define BT_DEBUG_STATES 4 /* Verbose look at state changes */ -/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized - value */ +/* + * BT_DEBUG_OFF must be zero to correspond to the default uninitialized + * value + */ static int bt_debug; /* 0 == BT_DEBUG_OFF */ module_param(bt_debug, int, 0644); MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); -/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, - and 64 byte buffers. However, one HP implementation wants 255 bytes of - buffer (with a documented message of 160 bytes) so go for the max. - Since the Open IPMI architecture is single-message oriented at this - stage, the queue depth of BT is of no concern. */ +/* + * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, + * and 64 byte buffers. However, one HP implementation wants 255 bytes of + * buffer (with a documented message of 160 bytes) so go for the max. + * Since the Open IPMI architecture is single-message oriented at this + * stage, the queue depth of BT is of no concern. + */ #define BT_NORMAL_TIMEOUT 5 /* seconds */ #define BT_NORMAL_RETRY_LIMIT 2 #define BT_RESET_DELAY 6 /* seconds after warm reset */ -/* States are written in chronological order and usually cover - multiple rows of the state table discussion in the IPMI spec. */ +/* + * States are written in chronological order and usually cover + * multiple rows of the state table discussion in the IPMI spec. + */ enum bt_states { BT_STATE_IDLE = 0, /* Order is critical in this list */ @@ -76,10 +82,12 @@ enum bt_states { BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ }; -/* Macros seen at the end of state "case" blocks. They help with legibility - and debugging. */ +/* + * Macros seen at the end of state "case" blocks. They help with legibility + * and debugging. + */ -#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; } +#define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; } #define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; } @@ -110,11 +118,13 @@ struct si_sm_data { #define BT_H_BUSY 0x40 #define BT_B_BUSY 0x80 -/* Some bits are toggled on each write: write once to set it, once - more to clear it; writing a zero does nothing. To absolutely - clear it, check its state and write if set. This avoids the "get - current then use as mask" scheme to modify one bit. Note that the - variable "bt" is hardcoded into these macros. */ +/* + * Some bits are toggled on each write: write once to set it, once + * more to clear it; writing a zero does nothing. To absolutely + * clear it, check its state and write if set. This avoids the "get + * current then use as mask" scheme to modify one bit. Note that the + * variable "bt" is hardcoded into these macros. + */ #define BT_STATUS bt->io->inputb(bt->io, 0) #define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x) @@ -125,8 +135,10 @@ struct si_sm_data { #define BT_INTMASK_R bt->io->inputb(bt->io, 2) #define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x) -/* Convenience routines for debugging. These are not multi-open safe! - Note the macros have hardcoded variables in them. */ +/* + * Convenience routines for debugging. These are not multi-open safe! + * Note the macros have hardcoded variables in them. + */ static char *state2txt(unsigned char state) { @@ -182,7 +194,8 @@ static char *status2txt(unsigned char status) static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) { memset(bt, 0, sizeof(struct si_sm_data)); - if (bt->io != io) { /* external: one-time only things */ + if (bt->io != io) { + /* external: one-time only things */ bt->io = io; bt->seq = 0; } @@ -229,7 +242,7 @@ static int bt_start_transaction(struct si_sm_data *bt, printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk (" %02x", data[i]); + printk(" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ @@ -246,8 +259,10 @@ static int bt_start_transaction(struct si_sm_data *bt, return 0; } -/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE - it calls this. Strip out the length and seq bytes. */ +/* + * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE + * it calls this. Strip out the length and seq bytes. + */ static int bt_get_result(struct si_sm_data *bt, unsigned char *data, @@ -269,10 +284,10 @@ static int bt_get_result(struct si_sm_data *bt, memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { - printk (KERN_WARNING "BT: result %d bytes:", msg_len); + printk(KERN_WARNING "BT: result %d bytes:", msg_len); for (i = 0; i < msg_len; i++) printk(" %02x", data[i]); - printk ("\n"); + printk("\n"); } return msg_len; } @@ -292,8 +307,10 @@ static void reset_flags(struct si_sm_data *bt) BT_INTMASK_W(BT_BMC_HWRST); } -/* Get rid of an unwanted/stale response. This should only be needed for - BMCs that support multiple outstanding requests. */ +/* + * Get rid of an unwanted/stale response. This should only be needed for + * BMCs that support multiple outstanding requests. + */ static void drain_BMC2HOST(struct si_sm_data *bt) { @@ -326,8 +343,8 @@ static inline void write_all_bytes(struct si_sm_data *bt) printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) - printk (" %02x", bt->write_data[i]); - printk ("\n"); + printk(" %02x", bt->write_data[i]); + printk("\n"); } for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); @@ -337,8 +354,10 @@ static inline int read_all_bytes(struct si_sm_data *bt) { unsigned char i; - /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. - Keep layout of first four bytes aligned with write_data[] */ + /* + * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. + * Keep layout of first four bytes aligned with write_data[] + */ bt->read_data[0] = BMC2HOST; bt->read_count = bt->read_data[0]; @@ -362,8 +381,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (max > 16) max = 16; for (i = 0; i < max; i++) - printk (" %02x", bt->read_data[i]); - printk ("%s\n", bt->read_count == max ? "" : " ..."); + printk(KERN_CONT " %02x", bt->read_data[i]); + printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ..."); } /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ @@ -402,8 +421,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ reason, STATE2TXT, STATUS2TXT); - /* Per the IPMI spec, retries are based on the sequence number - known only to this module, so manage a restart here. */ + /* + * Per the IPMI spec, retries are based on the sequence number + * known only to this module, so manage a restart here. + */ (bt->error_retries)++; if (bt->error_retries < bt->BT_CAP_retries) { printk("%d retries left\n", @@ -412,8 +433,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, return SI_SM_CALL_WITHOUT_DELAY; } - printk("failed %d retries, sending error response\n", - bt->BT_CAP_retries); + printk(KERN_WARNING "failed %d retries, sending error response\n", + bt->BT_CAP_retries); if (!bt->nonzero_status) printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); @@ -424,8 +445,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, return SI_SM_CALL_WITHOUT_DELAY; } - /* Concoct a useful error message, set up the next state, and - be done with this sequence. */ + /* + * Concoct a useful error message, set up the next state, and + * be done with this sequence. + */ bt->state = BT_STATE_IDLE; switch (cCode) { @@ -461,10 +484,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) last_printed = bt->state; } - /* Commands that time out may still (eventually) provide a response. - This stale response will get in the way of a new response so remove - it if possible (hopefully during IDLE). Even if it comes up later - it will be rejected by its (now-forgotten) seq number. */ + /* + * Commands that time out may still (eventually) provide a response. + * This stale response will get in the way of a new response so remove + * it if possible (hopefully during IDLE). Even if it comes up later + * it will be rejected by its (now-forgotten) seq number. + */ if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { drain_BMC2HOST(bt); @@ -472,7 +497,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) } if ((bt->state != BT_STATE_IDLE) && - (bt->state < BT_STATE_PRINTME)) { /* check timeout */ + (bt->state < BT_STATE_PRINTME)) { + /* check timeout */ bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) return error_recovery(bt, @@ -482,8 +508,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) switch (bt->state) { - /* Idle state first checks for asynchronous messages from another - channel, then does some opportunistic housekeeping. */ + /* + * Idle state first checks for asynchronous messages from another + * channel, then does some opportunistic housekeeping. + */ case BT_STATE_IDLE: if (status & BT_SMS_ATN) { @@ -531,16 +559,19 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); BT_CONTROL(BT_H_BUSY); /* set */ - /* Uncached, ordered writes should just proceeed serially but - some BMCs don't clear B2H_ATN with one hit. Fast-path a - workaround without too much penalty to the general case. */ + /* + * Uncached, ordered writes should just proceeed serially but + * some BMCs don't clear B2H_ATN with one hit. Fast-path a + * workaround without too much penalty to the general case. + */ BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_CLEAR_B2H: - if (status & BT_B2H_ATN) { /* keep hitting it */ + if (status & BT_B2H_ATN) { + /* keep hitting it */ BT_CONTROL(BT_B2H_ATN); BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); } @@ -548,7 +579,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_READ_BYTES: - if (!(status & BT_H_BUSY)) /* check in case of retry */ + if (!(status & BT_H_BUSY)) + /* check in case of retry */ BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ i = read_all_bytes(bt); /* true == packet seq match */ @@ -599,8 +631,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_STATE_CHANGE(BT_STATE_XACTION_START, SI_SM_CALL_WITH_DELAY); - /* Get BT Capabilities, using timing of upper level state machine. - Set outreqs to prevent infinite loop on timeout. */ + /* + * Get BT Capabilities, using timing of upper level state machine. + * Set outreqs to prevent infinite loop on timeout. + */ case BT_STATE_CAPABILITIES_BEGIN: bt->BT_CAP_outreqs = 1; { @@ -638,10 +672,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) static int bt_detect(struct si_sm_data *bt) { - /* It's impossible for the BT status and interrupt registers to be - all 1's, (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. The calling routine uses negative logic. */ + /* + * It's impossible for the BT status and interrupt registers to be + * all 1's, (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. The calling routine uses negative logic. + */ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1; @@ -658,8 +694,7 @@ static int bt_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers bt_smi_handlers = -{ +struct si_sm_handlers bt_smi_handlers = { .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index c1b8228cb7b6..80704875794c 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -60,37 +60,58 @@ MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); /* The states the KCS driver may be in. */ enum kcs_states { - KCS_IDLE, /* The KCS interface is currently - doing nothing. */ - KCS_START_OP, /* We are starting an operation. The - data is in the output buffer, but - nothing has been done to the - interface yet. This was added to - the state machine in the spec to - wait for the initial IBF. */ - KCS_WAIT_WRITE_START, /* We have written a write cmd to the - interface. */ - KCS_WAIT_WRITE, /* We are writing bytes to the - interface. */ - KCS_WAIT_WRITE_END, /* We have written the write end cmd - to the interface, and still need to - write the last byte. */ - KCS_WAIT_READ, /* We are waiting to read data from - the interface. */ - KCS_ERROR0, /* State to transition to the error - handler, this was added to the - state machine in the spec to be - sure IBF was there. */ - KCS_ERROR1, /* First stage error handler, wait for - the interface to respond. */ - KCS_ERROR2, /* The abort cmd has been written, - wait for the interface to - respond. */ - KCS_ERROR3, /* We wrote some data to the - interface, wait for it to switch to - read mode. */ - KCS_HOSED /* The hardware failed to follow the - state machine. */ + /* The KCS interface is currently doing nothing. */ + KCS_IDLE, + + /* + * We are starting an operation. The data is in the output + * buffer, but nothing has been done to the interface yet. This + * was added to the state machine in the spec to wait for the + * initial IBF. + */ + KCS_START_OP, + + /* We have written a write cmd to the interface. */ + KCS_WAIT_WRITE_START, + + /* We are writing bytes to the interface. */ + KCS_WAIT_WRITE, + + /* + * We have written the write end cmd to the interface, and + * still need to write the last byte. + */ + KCS_WAIT_WRITE_END, + + /* We are waiting to read data from the interface. */ + KCS_WAIT_READ, + + /* + * State to transition to the error handler, this was added to + * the state machine in the spec to be sure IBF was there. + */ + KCS_ERROR0, + + /* + * First stage error handler, wait for the interface to + * respond. + */ + KCS_ERROR1, + + /* + * The abort cmd has been written, wait for the interface to + * respond. + */ + KCS_ERROR2, + + /* + * We wrote some data to the interface, wait for it to switch + * to read mode. + */ + KCS_ERROR3, + + /* The hardware failed to follow the state machine. */ + KCS_HOSED }; #define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH @@ -102,8 +123,7 @@ enum kcs_states { #define MAX_ERROR_RETRIES 10 #define ERROR0_OBF_WAIT_JIFFIES (2*HZ) -struct si_sm_data -{ +struct si_sm_data { enum kcs_states state; struct si_sm_io *io; unsigned char write_data[MAX_KCS_WRITE_SIZE]; @@ -187,7 +207,8 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason) (kcs->error_retries)++; if (kcs->error_retries > MAX_ERROR_RETRIES) { if (kcs_debug & KCS_DEBUG_ENABLE) - printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); + printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", + reason); kcs->state = KCS_HOSED; } else { kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES; @@ -271,10 +292,9 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, if (kcs_debug & KCS_DEBUG_MSG) { printk(KERN_DEBUG "start_kcs_transaction -"); - for (i = 0; i < size; i ++) { + for (i = 0; i < size; i++) printk(" %02x", (unsigned char) (data [i])); - } - printk ("\n"); + printk("\n"); } kcs->error_retries = 0; memcpy(kcs->write_data, data, size); @@ -305,9 +325,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data, kcs->read_pos = 3; } if (kcs->truncated) { - /* Report a truncated error. We might overwrite - another error, but that's too bad, the user needs - to know it was truncated. */ + /* + * Report a truncated error. We might overwrite + * another error, but that's too bad, the user needs + * to know it was truncated. + */ data[2] = IPMI_ERR_MSG_TRUNCATED; kcs->truncated = 0; } @@ -315,9 +337,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data, return kcs->read_pos; } -/* This implements the state machine defined in the IPMI manual, see - that for details on how this works. Divide that flowchart into - sections delimited by "Wait for IBF" and this will become clear. */ +/* + * This implements the state machine defined in the IPMI manual, see + * that for details on how this works. Divide that flowchart into + * sections delimited by "Wait for IBF" and this will become clear. + */ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) { unsigned char status; @@ -388,11 +412,12 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_next_byte(kcs); } break; - + case KCS_WAIT_WRITE_END: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, - "Not in write state for write end"); + "Not in write state" + " for write end"); break; } clear_obf(kcs, status); @@ -413,13 +438,15 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { - /* We don't implement this exactly like the state - machine in the spec. Some broken hardware - does not write the final dummy byte to the - read register. Thus obf will never go high - here. We just go straight to idle, and we - handle clearing out obf in idle state if it - happens to come in. */ + /* + * We don't implement this exactly like the state + * machine in the spec. Some broken hardware + * does not write the final dummy byte to the + * read register. Thus obf will never go high + * here. We just go straight to idle, and we + * handle clearing out obf in idle state if it + * happens to come in. + */ clear_obf(kcs, status); kcs->orig_write_count = 0; kcs->state = KCS_IDLE; @@ -430,7 +457,8 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) case KCS_ERROR0: clear_obf(kcs, status); status = read_status(kcs); - if (GET_STATUS_OBF(status)) /* controller isn't responding */ + if (GET_STATUS_OBF(status)) + /* controller isn't responding */ if (time_before(jiffies, kcs->error0_timeout)) return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); @@ -442,7 +470,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_data(kcs, 0); kcs->state = KCS_ERROR2; break; - + case KCS_ERROR2: if (state != KCS_READ_STATE) { start_error_recovery(kcs, @@ -456,7 +484,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_data(kcs, KCS_READ_BYTE); kcs->state = KCS_ERROR3; break; - + case KCS_ERROR3: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, @@ -475,7 +503,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) return SI_SM_TRANSACTION_COMPLETE; } break; - + case KCS_HOSED: break; } @@ -495,10 +523,12 @@ static int kcs_size(void) static int kcs_detect(struct si_sm_data *kcs) { - /* It's impossible for the KCS status register to be all 1's, - (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. */ + /* + * It's impossible for the KCS status register to be all 1's, + * (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. + */ if (read_status(kcs) == 0xff) return 1; @@ -509,8 +539,7 @@ static void kcs_cleanup(struct si_sm_data *kcs) { } -struct si_sm_handlers kcs_smi_handlers = -{ +struct si_sm_handlers kcs_smi_handlers = { .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 32b2b22996dc..8a59aaa21be5 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -47,7 +47,7 @@ #define PFX "IPMI message handler: " -#define IPMI_DRIVER_VERSION "39.1" +#define IPMI_DRIVER_VERSION "39.2" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -63,16 +63,16 @@ static struct proc_dir_entry *proc_ipmi_root; #define MAX_EVENTS_IN_QUEUE 25 -/* Don't let a message sit in a queue forever, always time it with at lest - the max message timer. This is in milliseconds. */ +/* + * Don't let a message sit in a queue forever, always time it with at lest + * the max message timer. This is in milliseconds. + */ #define MAX_MSG_TIMEOUT 60000 - /* * The main "user" data structure. */ -struct ipmi_user -{ +struct ipmi_user { struct list_head link; /* Set to "0" when the user is destroyed. */ @@ -91,8 +91,7 @@ struct ipmi_user int gets_events; }; -struct cmd_rcvr -{ +struct cmd_rcvr { struct list_head link; ipmi_user_t user; @@ -106,12 +105,12 @@ struct cmd_rcvr * or change any data until the RCU period completes. So we * use this next variable during mass deletion so we can have * a list and don't have to wait and restart the search on - * every individual deletion of a command. */ + * every individual deletion of a command. + */ struct cmd_rcvr *next; }; -struct seq_table -{ +struct seq_table { unsigned int inuse : 1; unsigned int broadcast : 1; @@ -119,53 +118,60 @@ struct seq_table unsigned long orig_timeout; unsigned int retries_left; - /* To verify on an incoming send message response that this is - the message that the response is for, we keep a sequence id - and increment it every time we send a message. */ + /* + * To verify on an incoming send message response that this is + * the message that the response is for, we keep a sequence id + * and increment it every time we send a message. + */ long seqid; - /* This is held so we can properly respond to the message on a - timeout, and it is used to hold the temporary data for - retransmission, too. */ + /* + * This is held so we can properly respond to the message on a + * timeout, and it is used to hold the temporary data for + * retransmission, too. + */ struct ipmi_recv_msg *recv_msg; }; -/* Store the information in a msgid (long) to allow us to find a - sequence table entry from the msgid. */ +/* + * Store the information in a msgid (long) to allow us to find a + * sequence table entry from the msgid. + */ #define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff)) #define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \ do { \ seq = ((msgid >> 26) & 0x3f); \ seqid = (msgid & 0x3fffff); \ - } while (0) + } while (0) #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff) -struct ipmi_channel -{ +struct ipmi_channel { unsigned char medium; unsigned char protocol; - /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, - but may be changed by the user. */ + /* + * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, + * but may be changed by the user. + */ unsigned char address; - /* My LUN. This should generally stay the SMS LUN, but just in - case... */ + /* + * My LUN. This should generally stay the SMS LUN, but just in + * case... + */ unsigned char lun; }; #ifdef CONFIG_PROC_FS -struct ipmi_proc_entry -{ +struct ipmi_proc_entry { char *name; struct ipmi_proc_entry *next; }; #endif -struct bmc_device -{ +struct bmc_device { struct platform_device *dev; struct ipmi_device_id id; unsigned char guid[16]; @@ -186,10 +192,108 @@ struct bmc_device struct device_attribute aux_firmware_rev_attr; }; +/* + * Various statistics for IPMI, these index stats[] in the ipmi_smi + * structure. + */ +enum ipmi_stat_indexes { + /* Commands we got from the user that were invalid. */ + IPMI_STAT_sent_invalid_commands = 0, + + /* Commands we sent to the MC. */ + IPMI_STAT_sent_local_commands, + + /* Responses from the MC that were delivered to a user. */ + IPMI_STAT_handled_local_responses, + + /* Responses from the MC that were not delivered to a user. */ + IPMI_STAT_unhandled_local_responses, + + /* Commands we sent out to the IPMB bus. */ + IPMI_STAT_sent_ipmb_commands, + + /* Commands sent on the IPMB that had errors on the SEND CMD */ + IPMI_STAT_sent_ipmb_command_errs, + + /* Each retransmit increments this count. */ + IPMI_STAT_retransmitted_ipmb_commands, + + /* + * When a message times out (runs out of retransmits) this is + * incremented. + */ + IPMI_STAT_timed_out_ipmb_commands, + + /* + * This is like above, but for broadcasts. Broadcasts are + * *not* included in the above count (they are expected to + * time out). + */ + IPMI_STAT_timed_out_ipmb_broadcasts, + + /* Responses I have sent to the IPMB bus. */ + IPMI_STAT_sent_ipmb_responses, + + /* The response was delivered to the user. */ + IPMI_STAT_handled_ipmb_responses, + + /* The response had invalid data in it. */ + IPMI_STAT_invalid_ipmb_responses, + + /* The response didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_ipmb_responses, + + /* Commands we sent out to the IPMB bus. */ + IPMI_STAT_sent_lan_commands, + + /* Commands sent on the IPMB that had errors on the SEND CMD */ + IPMI_STAT_sent_lan_command_errs, + + /* Each retransmit increments this count. */ + IPMI_STAT_retransmitted_lan_commands, + + /* + * When a message times out (runs out of retransmits) this is + * incremented. + */ + IPMI_STAT_timed_out_lan_commands, + + /* Responses I have sent to the IPMB bus. */ + IPMI_STAT_sent_lan_responses, + + /* The response was delivered to the user. */ + IPMI_STAT_handled_lan_responses, + + /* The response had invalid data in it. */ + IPMI_STAT_invalid_lan_responses, + + /* The response didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_lan_responses, + + /* The command was delivered to the user. */ + IPMI_STAT_handled_commands, + + /* The command had invalid data in it. */ + IPMI_STAT_invalid_commands, + + /* The command didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_commands, + + /* Invalid data in an event. */ + IPMI_STAT_invalid_events, + + /* Events that were received with the proper format. */ + IPMI_STAT_events, + + + /* This *must* remain last, add new values above this. */ + IPMI_NUM_STATS +}; + + #define IPMI_IPMB_NUM_SEQ 64 #define IPMI_MAX_CHANNELS 16 -struct ipmi_smi -{ +struct ipmi_smi { /* What interface number are we? */ int intf_num; @@ -198,8 +302,10 @@ struct ipmi_smi /* Used for a list of interfaces. */ struct list_head link; - /* The list of upper layers that are using me. seq_lock - * protects this. */ + /* + * The list of upper layers that are using me. seq_lock + * protects this. + */ struct list_head users; /* Information to supply to users. */ @@ -213,10 +319,12 @@ struct ipmi_smi char *my_dev_name; char *sysfs_name; - /* This is the lower-layer's sender routine. Note that you + /* + * This is the lower-layer's sender routine. Note that you * must either be holding the ipmi_interfaces_mutex or be in * an umpreemptible region to use this. You must fetch the - * value into a local variable and make sure it is not NULL. */ + * value into a local variable and make sure it is not NULL. + */ struct ipmi_smi_handlers *handlers; void *send_info; @@ -229,34 +337,45 @@ struct ipmi_smi /* Driver-model device for the system interface. */ struct device *si_dev; - /* A table of sequence numbers for this interface. We use the - sequence numbers for IPMB messages that go out of the - interface to match them up with their responses. A routine - is called periodically to time the items in this list. */ + /* + * A table of sequence numbers for this interface. We use the + * sequence numbers for IPMB messages that go out of the + * interface to match them up with their responses. A routine + * is called periodically to time the items in this list. + */ spinlock_t seq_lock; struct seq_table seq_table[IPMI_IPMB_NUM_SEQ]; int curr_seq; - /* Messages that were delayed for some reason (out of memory, - for instance), will go in here to be processed later in a - periodic timer interrupt. */ + /* + * Messages that were delayed for some reason (out of memory, + * for instance), will go in here to be processed later in a + * periodic timer interrupt. + */ spinlock_t waiting_msgs_lock; struct list_head waiting_msgs; - /* The list of command receivers that are registered for commands - on this interface. */ + /* + * The list of command receivers that are registered for commands + * on this interface. + */ struct mutex cmd_rcvrs_mutex; struct list_head cmd_rcvrs; - /* Events that were queues because no one was there to receive - them. */ + /* + * Events that were queues because no one was there to receive + * them. + */ spinlock_t events_lock; /* For dealing with event stuff. */ struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ - int delivering_events; + char delivering_events; + char event_msg_printed; - /* The event receiver for my BMC, only really used at panic - shutdown as a place to store this. */ + /* + * The event receiver for my BMC, only really used at panic + * shutdown as a place to store this. + */ unsigned char event_receiver; unsigned char event_receiver_lun; unsigned char local_sel_device; @@ -268,14 +387,18 @@ struct ipmi_smi int auto_maintenance_timeout; spinlock_t maintenance_mode_lock; /* Used in a timer... */ - /* A cheap hack, if this is non-null and a message to an - interface comes in with a NULL user, call this routine with - it. Note that the message will still be freed by the - caller. This only works on the system interface. */ + /* + * A cheap hack, if this is non-null and a message to an + * interface comes in with a NULL user, call this routine with + * it. Note that the message will still be freed by the + * caller. This only works on the system interface. + */ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); - /* When we are scanning the channels for an SMI, this will - tell which channel we are scanning. */ + /* + * When we are scanning the channels for an SMI, this will + * tell which channel we are scanning. + */ int curr_channel; /* Channel information */ @@ -285,74 +408,14 @@ struct ipmi_smi struct proc_dir_entry *proc_dir; char proc_dir_name[10]; - spinlock_t counter_lock; /* For making counters atomic. */ - - /* Commands we got that were invalid. */ - unsigned int sent_invalid_commands; - - /* Commands we sent to the MC. */ - unsigned int sent_local_commands; - /* Responses from the MC that were delivered to a user. */ - unsigned int handled_local_responses; - /* Responses from the MC that were not delivered to a user. */ - unsigned int unhandled_local_responses; - - /* Commands we sent out to the IPMB bus. */ - unsigned int sent_ipmb_commands; - /* Commands sent on the IPMB that had errors on the SEND CMD */ - unsigned int sent_ipmb_command_errs; - /* Each retransmit increments this count. */ - unsigned int retransmitted_ipmb_commands; - /* When a message times out (runs out of retransmits) this is - incremented. */ - unsigned int timed_out_ipmb_commands; - - /* This is like above, but for broadcasts. Broadcasts are - *not* included in the above count (they are expected to - time out). */ - unsigned int timed_out_ipmb_broadcasts; + atomic_t stats[IPMI_NUM_STATS]; - /* Responses I have sent to the IPMB bus. */ - unsigned int sent_ipmb_responses; - - /* The response was delivered to the user. */ - unsigned int handled_ipmb_responses; - /* The response had invalid data in it. */ - unsigned int invalid_ipmb_responses; - /* The response didn't have anyone waiting for it. */ - unsigned int unhandled_ipmb_responses; - - /* Commands we sent out to the IPMB bus. */ - unsigned int sent_lan_commands; - /* Commands sent on the IPMB that had errors on the SEND CMD */ - unsigned int sent_lan_command_errs; - /* Each retransmit increments this count. */ - unsigned int retransmitted_lan_commands; - /* When a message times out (runs out of retransmits) this is - incremented. */ - unsigned int timed_out_lan_commands; - - /* Responses I have sent to the IPMB bus. */ - unsigned int sent_lan_responses; - - /* The response was delivered to the user. */ - unsigned int handled_lan_responses; - /* The response had invalid data in it. */ - unsigned int invalid_lan_responses; - /* The response didn't have anyone waiting for it. */ - unsigned int unhandled_lan_responses; - - /* The command was delivered to the user. */ - unsigned int handled_commands; - /* The command had invalid data in it. */ - unsigned int invalid_commands; - /* The command didn't have anyone waiting for it. */ - unsigned int unhandled_commands; - - /* Invalid data in an event. */ - unsigned int invalid_events; - /* Events that were received with the proper format. */ - unsigned int events; + /* + * run_to_completion duplicate of smb_info, smi_info + * and ipmi_serial_info structures. Used to decrease numbers of + * parameters passed by "low" level IPMI code. + */ + int run_to_completion; }; #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) @@ -368,12 +431,19 @@ static DEFINE_MUTEX(ipmidriver_mutex); static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); -/* List of watchers that want to know when smi's are added and - deleted. */ +/* + * List of watchers that want to know when smi's are added and deleted. + */ static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); +#define ipmi_inc_stat(intf, stat) \ + atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat]) +#define ipmi_get_stat(intf, stat) \ + ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat])) + + static void free_recv_msg_list(struct list_head *q) { struct ipmi_recv_msg *msg, *msg2; @@ -417,10 +487,8 @@ static void clean_up_interface_data(ipmi_smi_t intf) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if ((intf->seq_table[i].inuse) - && (intf->seq_table[i].recv_msg)) - { + && (intf->seq_table[i].recv_msg)) ipmi_free_recv_msg(intf->seq_table[i].recv_msg); - } } } @@ -487,6 +555,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) } return -ENOMEM; } +EXPORT_SYMBOL(ipmi_smi_watcher_register); int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) { @@ -495,6 +564,7 @@ int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) mutex_unlock(&smi_watchers_mutex); return 0; } +EXPORT_SYMBOL(ipmi_smi_watcher_unregister); /* * Must be called with smi_watchers_mutex held. @@ -530,8 +600,7 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) } if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr1 = (struct ipmi_ipmb_addr *) addr1; struct ipmi_ipmb_addr *ipmb_addr2 @@ -559,9 +628,8 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) int ipmi_validate_addr(struct ipmi_addr *addr, int len) { - if (len < sizeof(struct ipmi_system_interface_addr)) { + if (len < sizeof(struct ipmi_system_interface_addr)) return -EINVAL; - } if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { if (addr->channel != IPMI_BMC_CHANNEL) @@ -575,23 +643,21 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len) return -EINVAL; if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { - if (len < sizeof(struct ipmi_ipmb_addr)) { + || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { + if (len < sizeof(struct ipmi_ipmb_addr)) return -EINVAL; - } return 0; } if (addr->addr_type == IPMI_LAN_ADDR_TYPE) { - if (len < sizeof(struct ipmi_lan_addr)) { + if (len < sizeof(struct ipmi_lan_addr)) return -EINVAL; - } return 0; } return -EINVAL; } +EXPORT_SYMBOL(ipmi_validate_addr); unsigned int ipmi_addr_length(int addr_type) { @@ -599,34 +665,28 @@ unsigned int ipmi_addr_length(int addr_type) return sizeof(struct ipmi_system_interface_addr); if ((addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) return sizeof(struct ipmi_ipmb_addr); - } if (addr_type == IPMI_LAN_ADDR_TYPE) return sizeof(struct ipmi_lan_addr); return 0; } +EXPORT_SYMBOL(ipmi_addr_length); static void deliver_response(struct ipmi_recv_msg *msg) { if (!msg->user) { ipmi_smi_t intf = msg->user_msg_data; - unsigned long flags; /* Special handling for NULL users. */ if (intf->null_user_handler) { intf->null_user_handler(intf, msg); - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_local_responses); } else { /* No handler, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_local_responses); } ipmi_free_recv_msg(msg); } else { @@ -646,9 +706,11 @@ deliver_err_response(struct ipmi_recv_msg *msg, int err) deliver_response(msg); } -/* Find the next sequence number not being used and add the given - message with the given timeout to the sequence table. This must be - called with the interface's seq_lock held. */ +/* + * Find the next sequence number not being used and add the given + * message with the given timeout to the sequence table. This must be + * called with the interface's seq_lock held. + */ static int intf_next_seq(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, unsigned long timeout, @@ -660,10 +722,8 @@ static int intf_next_seq(ipmi_smi_t intf, int rv = 0; unsigned int i; - for (i = intf->curr_seq; - (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; - i = (i+1)%IPMI_IPMB_NUM_SEQ) - { + for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; + i = (i+1)%IPMI_IPMB_NUM_SEQ) { if (!intf->seq_table[i].inuse) break; } @@ -671,8 +731,10 @@ static int intf_next_seq(ipmi_smi_t intf, if (!intf->seq_table[i].inuse) { intf->seq_table[i].recv_msg = recv_msg; - /* Start with the maximum timeout, when the send response - comes in we will start the real timer. */ + /* + * Start with the maximum timeout, when the send response + * comes in we will start the real timer. + */ intf->seq_table[i].timeout = MAX_MSG_TIMEOUT; intf->seq_table[i].orig_timeout = timeout; intf->seq_table[i].retries_left = retries; @@ -685,15 +747,17 @@ static int intf_next_seq(ipmi_smi_t intf, } else { rv = -EAGAIN; } - + return rv; } -/* Return the receive message for the given sequence number and - release the sequence number so it can be reused. Some other data - is passed in to be sure the message matches up correctly (to help - guard against message coming in after their timeout and the - sequence number being reused). */ +/* + * Return the receive message for the given sequence number and + * release the sequence number so it can be reused. Some other data + * is passed in to be sure the message matches up correctly (to help + * guard against message coming in after their timeout and the + * sequence number being reused). + */ static int intf_find_seq(ipmi_smi_t intf, unsigned char seq, short channel, @@ -712,11 +776,9 @@ static int intf_find_seq(ipmi_smi_t intf, if (intf->seq_table[seq].inuse) { struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg; - if ((msg->addr.channel == channel) - && (msg->msg.cmd == cmd) - && (msg->msg.netfn == netfn) - && (ipmi_addr_equal(addr, &(msg->addr)))) - { + if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd) + && (msg->msg.netfn == netfn) + && (ipmi_addr_equal(addr, &(msg->addr)))) { *recv_msg = msg; intf->seq_table[seq].inuse = 0; rv = 0; @@ -741,11 +803,12 @@ static int intf_start_seq_timer(ipmi_smi_t intf, GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); - /* We do this verification because the user can be deleted - while a message is outstanding. */ + /* + * We do this verification because the user can be deleted + * while a message is outstanding. + */ if ((intf->seq_table[seq].inuse) - && (intf->seq_table[seq].seqid == seqid)) - { + && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->timeout = ent->orig_timeout; rv = 0; @@ -770,11 +833,12 @@ static int intf_err_seq(ipmi_smi_t intf, GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); - /* We do this verification because the user can be deleted - while a message is outstanding. */ + /* + * We do this verification because the user can be deleted + * while a message is outstanding. + */ if ((intf->seq_table[seq].inuse) - && (intf->seq_table[seq].seqid == seqid)) - { + && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->inuse = 0; @@ -800,24 +864,30 @@ int ipmi_create_user(unsigned int if_num, int rv = 0; ipmi_smi_t intf; - /* There is no module usecount here, because it's not - required. Since this can only be used by and called from - other modules, they will implicitly use this module, and - thus this can't be removed unless the other modules are - removed. */ + /* + * There is no module usecount here, because it's not + * required. Since this can only be used by and called from + * other modules, they will implicitly use this module, and + * thus this can't be removed unless the other modules are + * removed. + */ if (handler == NULL) return -EINVAL; - /* Make sure the driver is actually initialized, this handles - problems with initialization order. */ + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; - /* The init code doesn't return an error if it was turned - off, but it won't initialize. Check that. */ + /* + * The init code doesn't return an error if it was turned + * off, but it won't initialize. Check that. + */ if (!initialized) return -ENODEV; } @@ -858,8 +928,10 @@ int ipmi_create_user(unsigned int if_num, } } - /* Hold the lock so intf->handlers is guaranteed to be good - * until now */ + /* + * Hold the lock so intf->handlers is guaranteed to be good + * until now + */ mutex_unlock(&ipmi_interfaces_mutex); new_user->valid = 1; @@ -876,6 +948,7 @@ out_kfree: kfree(new_user); return rv; } +EXPORT_SYMBOL(ipmi_create_user); static void free_user(struct kref *ref) { @@ -899,8 +972,7 @@ int ipmi_destroy_user(ipmi_user_t user) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if (intf->seq_table[i].inuse - && (intf->seq_table[i].recv_msg->user == user)) - { + && (intf->seq_table[i].recv_msg->user == user)) { intf->seq_table[i].inuse = 0; ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } @@ -943,6 +1015,7 @@ int ipmi_destroy_user(ipmi_user_t user) return 0; } +EXPORT_SYMBOL(ipmi_destroy_user); void ipmi_get_version(ipmi_user_t user, unsigned char *major, @@ -951,6 +1024,7 @@ void ipmi_get_version(ipmi_user_t user, *major = user->intf->ipmi_version_major; *minor = user->intf->ipmi_version_minor; } +EXPORT_SYMBOL(ipmi_get_version); int ipmi_set_my_address(ipmi_user_t user, unsigned int channel, @@ -961,6 +1035,7 @@ int ipmi_set_my_address(ipmi_user_t user, user->intf->channels[channel].address = address; return 0; } +EXPORT_SYMBOL(ipmi_set_my_address); int ipmi_get_my_address(ipmi_user_t user, unsigned int channel, @@ -971,6 +1046,7 @@ int ipmi_get_my_address(ipmi_user_t user, *address = user->intf->channels[channel].address; return 0; } +EXPORT_SYMBOL(ipmi_get_my_address); int ipmi_set_my_LUN(ipmi_user_t user, unsigned int channel, @@ -981,6 +1057,7 @@ int ipmi_set_my_LUN(ipmi_user_t user, user->intf->channels[channel].lun = LUN & 0x3; return 0; } +EXPORT_SYMBOL(ipmi_set_my_LUN); int ipmi_get_my_LUN(ipmi_user_t user, unsigned int channel, @@ -991,6 +1068,7 @@ int ipmi_get_my_LUN(ipmi_user_t user, *address = user->intf->channels[channel].lun; return 0; } +EXPORT_SYMBOL(ipmi_get_my_LUN); int ipmi_get_maintenance_mode(ipmi_user_t user) { @@ -1075,6 +1153,11 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; + if (intf->event_msg_printed) { + printk(KERN_WARNING PFX "Event queue no longer" + " full\n"); + intf->event_msg_printed = 0; + } intf->delivering_events = 1; spin_unlock_irqrestore(&intf->events_lock, flags); @@ -1094,6 +1177,7 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) return 0; } +EXPORT_SYMBOL(ipmi_set_gets_events); static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, unsigned char netfn, @@ -1159,6 +1243,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, return rv; } +EXPORT_SYMBOL(ipmi_register_for_cmd); int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, @@ -1196,19 +1281,13 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, } return rv; } - -void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) -{ - ipmi_smi_t intf = user->intf; - if (intf->handlers) - intf->handlers->set_run_to_completion(intf->send_info, val); -} +EXPORT_SYMBOL(ipmi_unregister_for_cmd); static unsigned char ipmb_checksum(unsigned char *data, int size) { unsigned char csum = 0; - + for (; size > 0; size--, data++) csum += *data; @@ -1250,8 +1329,10 @@ static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg, = ipmb_checksum(&(smi_msg->data[i+6]), smi_msg->data_size-6); - /* Add on the checksum size and the offset from the - broadcast. */ + /* + * Add on the checksum size and the offset from the + * broadcast. + */ smi_msg->data_size += 1 + i; smi_msg->msgid = msgid; @@ -1287,17 +1368,21 @@ static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg, = ipmb_checksum(&(smi_msg->data[7]), smi_msg->data_size-7); - /* Add on the checksum size and the offset from the - broadcast. */ + /* + * Add on the checksum size and the offset from the + * broadcast. + */ smi_msg->data_size += 1; smi_msg->msgid = msgid; } -/* Separate from ipmi_request so that the user does not have to be - supplied in certain circumstances (mainly at panic time). If - messages are supplied, they will be freed, even if an error - occurs. */ +/* + * Separate from ipmi_request so that the user does not have to be + * supplied in certain circumstances (mainly at panic time). If + * messages are supplied, they will be freed, even if an error + * occurs. + */ static int i_ipmi_request(ipmi_user_t user, ipmi_smi_t intf, struct ipmi_addr *addr, @@ -1319,19 +1404,18 @@ static int i_ipmi_request(ipmi_user_t user, struct ipmi_smi_handlers *handlers; - if (supplied_recv) { + if (supplied_recv) recv_msg = supplied_recv; - } else { + else { recv_msg = ipmi_alloc_recv_msg(); - if (recv_msg == NULL) { + if (recv_msg == NULL) return -ENOMEM; - } } recv_msg->user_msg_data = user_msg_data; - if (supplied_smi) { + if (supplied_smi) smi_msg = (struct ipmi_smi_msg *) supplied_smi; - } else { + else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { ipmi_free_recv_msg(recv_msg); @@ -1350,8 +1434,10 @@ static int i_ipmi_request(ipmi_user_t user, if (user) kref_get(&user->refcount); recv_msg->msgid = msgid; - /* Store the message to send in the receive message so timeout - responses can get the proper response data. */ + /* + * Store the message to send in the receive message so timeout + * responses can get the proper response data. + */ recv_msg->msg = *msg; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { @@ -1365,9 +1451,7 @@ static int i_ipmi_request(ipmi_user_t user, smi_addr = (struct ipmi_system_interface_addr *) addr; if (smi_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1377,13 +1461,12 @@ static int i_ipmi_request(ipmi_user_t user, if ((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_SEND_MSG_CMD) || (msg->cmd == IPMI_GET_MSG_CMD) - || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) - { - /* We don't let the user do these, since we manage - the sequence numbers. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) { + /* + * We don't let the user do these, since we manage + * the sequence numbers. + */ + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1391,14 +1474,12 @@ static int i_ipmi_request(ipmi_user_t user, if (((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_COLD_RESET_CMD) || (msg->cmd == IPMI_WARM_RESET_CMD))) - || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) - { + || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) { spin_lock_irqsave(&intf->maintenance_mode_lock, flags); intf->auto_maintenance_timeout = IPMI_MAINTENANCE_MODE_TIMEOUT; if (!intf->maintenance_mode - && !intf->maintenance_mode_enable) - { + && !intf->maintenance_mode_enable) { intf->maintenance_mode_enable = 1; maintenance_mode_update(intf); } @@ -1407,9 +1488,7 @@ static int i_ipmi_request(ipmi_user_t user, } if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } @@ -1421,31 +1500,23 @@ static int i_ipmi_request(ipmi_user_t user, if (msg->data_len > 0) memcpy(&(smi_msg->data[2]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 2; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_local_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_local_commands); } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr; unsigned char ipmb_seq; long seqid; int broadcast = 0; if (addr->channel >= IPMI_MAX_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } if (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_IPMB) - { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + != IPMI_CHANNEL_MEDIUM_IPMB) { + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1457,9 +1528,11 @@ static int i_ipmi_request(ipmi_user_t user, retries = 4; } if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) { - /* Broadcasts add a zero at the beginning of the - message, but otherwise is the same as an IPMB - address. */ + /* + * Broadcasts add a zero at the beginning of the + * message, but otherwise is the same as an IPMB + * address. + */ addr->addr_type = IPMI_IPMB_ADDR_TYPE; broadcast = 1; } @@ -1469,21 +1542,19 @@ static int i_ipmi_request(ipmi_user_t user, if (retry_time_ms == 0) retry_time_ms = 1000; - /* 9 for the header and 1 for the checksum, plus - possibly one for the broadcast. */ + /* + * 9 for the header and 1 for the checksum, plus + * possibly one for the broadcast. + */ if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } ipmb_addr = (struct ipmi_ipmb_addr *) addr; if (ipmb_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1491,29 +1562,31 @@ static int i_ipmi_request(ipmi_user_t user, memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr)); if (recv_msg->msg.netfn & 0x1) { - /* It's a response, so use the user's sequence - from msgid. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + /* + * It's a response, so use the user's sequence + * from msgid. + */ + ipmi_inc_stat(intf, sent_ipmb_responses); format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid, msgid, broadcast, source_address, source_lun); - /* Save the receive message so we can use it - to deliver the response. */ + /* + * Save the receive message so we can use it + * to deliver the response. + */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); - spin_lock(&intf->counter_lock); - intf->sent_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, sent_ipmb_commands); - /* Create a sequence number with a 1 second - timeout and 4 retries. */ + /* + * Create a sequence number with a 1 second + * timeout and 4 retries. + */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, @@ -1522,34 +1595,42 @@ static int i_ipmi_request(ipmi_user_t user, &ipmb_seq, &seqid); if (rv) { - /* We have used up all the sequence numbers, - probably, so abort. */ + /* + * We have used up all the sequence numbers, + * probably, so abort. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } - /* Store the sequence number in the message, - so that when the send message response - comes back we can start the timer. */ + /* + * Store the sequence number in the message, + * so that when the send message response + * comes back we can start the timer. + */ format_ipmb_msg(smi_msg, msg, ipmb_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, broadcast, source_address, source_lun); - /* Copy the message into the recv message data, so we - can retransmit it later if necessary. */ + /* + * Copy the message into the recv message data, so we + * can retransmit it later if necessary. + */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; - /* We don't unlock until here, because we need - to copy the completed message into the - recv_msg before we release the lock. - Otherwise, race conditions may bite us. I - know that's pretty paranoid, but I prefer - to be correct. */ + /* + * We don't unlock until here, because we need + * to copy the completed message into the + * recv_msg before we release the lock. + * Otherwise, race conditions may bite us. I + * know that's pretty paranoid, but I prefer + * to be correct. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) { @@ -1558,21 +1639,16 @@ static int i_ipmi_request(ipmi_user_t user, long seqid; if (addr->channel >= IPMI_MAX_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } if ((intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_8023LAN) + != IPMI_CHANNEL_MEDIUM_8023LAN) && (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_ASYNC)) - { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + != IPMI_CHANNEL_MEDIUM_ASYNC)) { + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1585,18 +1661,14 @@ static int i_ipmi_request(ipmi_user_t user, /* 11 for the header and 1 for the checksum. */ if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } lan_addr = (struct ipmi_lan_addr *) addr; if (lan_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1604,28 +1676,30 @@ static int i_ipmi_request(ipmi_user_t user, memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr)); if (recv_msg->msg.netfn & 0x1) { - /* It's a response, so use the user's sequence - from msgid. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + /* + * It's a response, so use the user's sequence + * from msgid. + */ + ipmi_inc_stat(intf, sent_lan_responses); format_lan_msg(smi_msg, msg, lan_addr, msgid, msgid, source_lun); - /* Save the receive message so we can use it - to deliver the response. */ + /* + * Save the receive message so we can use it + * to deliver the response. + */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); - spin_lock(&intf->counter_lock); - intf->sent_lan_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, sent_lan_commands); - /* Create a sequence number with a 1 second - timeout and 4 retries. */ + /* + * Create a sequence number with a 1 second + * timeout and 4 retries. + */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, @@ -1634,40 +1708,46 @@ static int i_ipmi_request(ipmi_user_t user, &ipmb_seq, &seqid); if (rv) { - /* We have used up all the sequence numbers, - probably, so abort. */ + /* + * We have used up all the sequence numbers, + * probably, so abort. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } - /* Store the sequence number in the message, - so that when the send message response - comes back we can start the timer. */ + /* + * Store the sequence number in the message, + * so that when the send message response + * comes back we can start the timer. + */ format_lan_msg(smi_msg, msg, lan_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, source_lun); - /* Copy the message into the recv message data, so we - can retransmit it later if necessary. */ + /* + * Copy the message into the recv message data, so we + * can retransmit it later if necessary. + */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; - /* We don't unlock until here, because we need - to copy the completed message into the - recv_msg before we release the lock. - Otherwise, race conditions may bite us. I - know that's pretty paranoid, but I prefer - to be correct. */ + /* + * We don't unlock until here, because we need + * to copy the completed message into the + * recv_msg before we release the lock. + * Otherwise, race conditions may bite us. I + * know that's pretty paranoid, but I prefer + * to be correct. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else { /* Unknown address type. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1735,6 +1815,7 @@ int ipmi_request_settime(ipmi_user_t user, retries, retry_time_ms); } +EXPORT_SYMBOL(ipmi_request_settime); int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_addr *addr, @@ -1766,6 +1847,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, lun, -1, 0); } +EXPORT_SYMBOL(ipmi_request_supply_msgs); #ifdef CONFIG_PROC_FS static int ipmb_file_read_proc(char *page, char **start, off_t off, @@ -1790,7 +1872,7 @@ static int version_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; - return sprintf(out, "%d.%d\n", + return sprintf(out, "%u.%u\n", ipmi_version_major(&intf->bmc->id), ipmi_version_minor(&intf->bmc->id)); } @@ -1801,65 +1883,65 @@ static int stat_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; - out += sprintf(out, "sent_invalid_commands: %d\n", - intf->sent_invalid_commands); - out += sprintf(out, "sent_local_commands: %d\n", - intf->sent_local_commands); - out += sprintf(out, "handled_local_responses: %d\n", - intf->handled_local_responses); - out += sprintf(out, "unhandled_local_responses: %d\n", - intf->unhandled_local_responses); - out += sprintf(out, "sent_ipmb_commands: %d\n", - intf->sent_ipmb_commands); - out += sprintf(out, "sent_ipmb_command_errs: %d\n", - intf->sent_ipmb_command_errs); - out += sprintf(out, "retransmitted_ipmb_commands: %d\n", - intf->retransmitted_ipmb_commands); - out += sprintf(out, "timed_out_ipmb_commands: %d\n", - intf->timed_out_ipmb_commands); - out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n", - intf->timed_out_ipmb_broadcasts); - out += sprintf(out, "sent_ipmb_responses: %d\n", - intf->sent_ipmb_responses); - out += sprintf(out, "handled_ipmb_responses: %d\n", - intf->handled_ipmb_responses); - out += sprintf(out, "invalid_ipmb_responses: %d\n", - intf->invalid_ipmb_responses); - out += sprintf(out, "unhandled_ipmb_responses: %d\n", - intf->unhandled_ipmb_responses); - out += sprintf(out, "sent_lan_commands: %d\n", - intf->sent_lan_commands); - out += sprintf(out, "sent_lan_command_errs: %d\n", - intf->sent_lan_command_errs); - out += sprintf(out, "retransmitted_lan_commands: %d\n", - intf->retransmitted_lan_commands); - out += sprintf(out, "timed_out_lan_commands: %d\n", - intf->timed_out_lan_commands); - out += sprintf(out, "sent_lan_responses: %d\n", - intf->sent_lan_responses); - out += sprintf(out, "handled_lan_responses: %d\n", - intf->handled_lan_responses); - out += sprintf(out, "invalid_lan_responses: %d\n", - intf->invalid_lan_responses); - out += sprintf(out, "unhandled_lan_responses: %d\n", - intf->unhandled_lan_responses); - out += sprintf(out, "handled_commands: %d\n", - intf->handled_commands); - out += sprintf(out, "invalid_commands: %d\n", - intf->invalid_commands); - out += sprintf(out, "unhandled_commands: %d\n", - intf->unhandled_commands); - out += sprintf(out, "invalid_events: %d\n", - intf->invalid_events); - out += sprintf(out, "events: %d\n", - intf->events); + out += sprintf(out, "sent_invalid_commands: %u\n", + ipmi_get_stat(intf, sent_invalid_commands)); + out += sprintf(out, "sent_local_commands: %u\n", + ipmi_get_stat(intf, sent_local_commands)); + out += sprintf(out, "handled_local_responses: %u\n", + ipmi_get_stat(intf, handled_local_responses)); + out += sprintf(out, "unhandled_local_responses: %u\n", + ipmi_get_stat(intf, unhandled_local_responses)); + out += sprintf(out, "sent_ipmb_commands: %u\n", + ipmi_get_stat(intf, sent_ipmb_commands)); + out += sprintf(out, "sent_ipmb_command_errs: %u\n", + ipmi_get_stat(intf, sent_ipmb_command_errs)); + out += sprintf(out, "retransmitted_ipmb_commands: %u\n", + ipmi_get_stat(intf, retransmitted_ipmb_commands)); + out += sprintf(out, "timed_out_ipmb_commands: %u\n", + ipmi_get_stat(intf, timed_out_ipmb_commands)); + out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n", + ipmi_get_stat(intf, timed_out_ipmb_broadcasts)); + out += sprintf(out, "sent_ipmb_responses: %u\n", + ipmi_get_stat(intf, sent_ipmb_responses)); + out += sprintf(out, "handled_ipmb_responses: %u\n", + ipmi_get_stat(intf, handled_ipmb_responses)); + out += sprintf(out, "invalid_ipmb_responses: %u\n", + ipmi_get_stat(intf, invalid_ipmb_responses)); + out += sprintf(out, "unhandled_ipmb_responses: %u\n", + ipmi_get_stat(intf, unhandled_ipmb_responses)); + out += sprintf(out, "sent_lan_commands: %u\n", + ipmi_get_stat(intf, sent_lan_commands)); + out += sprintf(out, "sent_lan_command_errs: %u\n", + ipmi_get_stat(intf, sent_lan_command_errs)); + out += sprintf(out, "retransmitted_lan_commands: %u\n", + ipmi_get_stat(intf, retransmitted_lan_commands)); + out += sprintf(out, "timed_out_lan_commands: %u\n", + ipmi_get_stat(intf, timed_out_lan_commands)); + out += sprintf(out, "sent_lan_responses: %u\n", + ipmi_get_stat(intf, sent_lan_responses)); + out += sprintf(out, "handled_lan_responses: %u\n", + ipmi_get_stat(intf, handled_lan_responses)); + out += sprintf(out, "invalid_lan_responses: %u\n", + ipmi_get_stat(intf, invalid_lan_responses)); + out += sprintf(out, "unhandled_lan_responses: %u\n", + ipmi_get_stat(intf, unhandled_lan_responses)); + out += sprintf(out, "handled_commands: %u\n", + ipmi_get_stat(intf, handled_commands)); + out += sprintf(out, "invalid_commands: %u\n", + ipmi_get_stat(intf, invalid_commands)); + out += sprintf(out, "unhandled_commands: %u\n", + ipmi_get_stat(intf, unhandled_commands)); + out += sprintf(out, "invalid_events: %u\n", + ipmi_get_stat(intf, invalid_events)); + out += sprintf(out, "events: %u\n", + ipmi_get_stat(intf, events)); return (out - ((char *) page)); } #endif /* CONFIG_PROC_FS */ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, - read_proc_t *read_proc, write_proc_t *write_proc, + read_proc_t *read_proc, void *data, struct module *owner) { int rv = 0; @@ -1886,7 +1968,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, } else { file->data = data; file->read_proc = read_proc; - file->write_proc = write_proc; file->owner = owner; mutex_lock(&smi->proc_entry_lock); @@ -1899,6 +1980,7 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, return rv; } +EXPORT_SYMBOL(ipmi_smi_add_proc_entry); static int add_proc_entries(ipmi_smi_t smi, int num) { @@ -1909,23 +1991,22 @@ static int add_proc_entries(ipmi_smi_t smi, int num) smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); if (!smi->proc_dir) rv = -ENOMEM; - else { + else smi->proc_dir->owner = THIS_MODULE; - } if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "stats", - stat_file_read_proc, NULL, + stat_file_read_proc, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "ipmb", - ipmb_file_read_proc, NULL, + ipmb_file_read_proc, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "version", - version_file_read_proc, NULL, + version_file_read_proc, smi, THIS_MODULE); #endif /* CONFIG_PROC_FS */ @@ -2210,37 +2291,47 @@ static int create_files(struct bmc_device *bmc) err = device_create_file(&bmc->dev->dev, &bmc->device_id_attr); - if (err) goto out; + if (err) + goto out; err = device_create_file(&bmc->dev->dev, &bmc->provides_dev_sdrs_attr); - if (err) goto out_devid; + if (err) + goto out_devid; err = device_create_file(&bmc->dev->dev, &bmc->revision_attr); - if (err) goto out_sdrs; + if (err) + goto out_sdrs; err = device_create_file(&bmc->dev->dev, &bmc->firmware_rev_attr); - if (err) goto out_rev; + if (err) + goto out_rev; err = device_create_file(&bmc->dev->dev, &bmc->version_attr); - if (err) goto out_firm; + if (err) + goto out_firm; err = device_create_file(&bmc->dev->dev, &bmc->add_dev_support_attr); - if (err) goto out_version; + if (err) + goto out_version; err = device_create_file(&bmc->dev->dev, &bmc->manufacturer_id_attr); - if (err) goto out_add_dev; + if (err) + goto out_add_dev; err = device_create_file(&bmc->dev->dev, &bmc->product_id_attr); - if (err) goto out_manu; + if (err) + goto out_manu; if (bmc->id.aux_firmware_revision_set) { err = device_create_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); - if (err) goto out_prod_id; + if (err) + goto out_prod_id; } if (bmc->guid_set) { err = device_create_file(&bmc->dev->dev, &bmc->guid_attr); - if (err) goto out_aux_firm; + if (err) + goto out_aux_firm; } return 0; @@ -2368,8 +2459,10 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum, "ipmi_msghandler:" " Unable to register bmc device: %d\n", rv); - /* Don't go to out_err, you can only do that if - the device is registered already. */ + /* + * Don't go to out_err, you can only do that if + * the device is registered already. + */ return rv; } @@ -2560,17 +2653,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) - && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) - { + && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) { - /* If the MC does not support this - command, that is legal. We just - assume it has one IPMB at channel - zero. */ + /* + * If the MC does not support this + * command, that is legal. We just + * assume it has one IPMB at channel + * zero. + */ intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->channels[0].protocol @@ -2591,7 +2685,7 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) intf->channels[chan].medium = msg->msg.data[2] & 0x7f; intf->channels[chan].protocol = msg->msg.data[3] & 0x1f; - next_channel: + next_channel: intf->curr_channel++; if (intf->curr_channel >= IPMI_MAX_CHANNELS) wake_up(&intf->waitq); @@ -2619,6 +2713,7 @@ void ipmi_poll_interface(ipmi_user_t user) if (intf->handlers->poll) intf->handlers->poll(intf->send_info); } +EXPORT_SYMBOL(ipmi_poll_interface); int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, @@ -2633,14 +2728,18 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ipmi_smi_t tintf; struct list_head *link; - /* Make sure the driver is actually initialized, this handles - problems with initialization order. */ + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; - /* The init code doesn't return an error if it was turned - off, but it won't initialize. Check that. */ + /* + * The init code doesn't return an error if it was turned + * off, but it won't initialize. Check that. + */ if (!initialized) return -ENODEV; } @@ -2688,8 +2787,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, spin_lock_init(&intf->maintenance_mode_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); + for (i = 0; i < IPMI_NUM_STATS; i++) + atomic_set(&intf->stats[i], 0); - spin_lock_init(&intf->counter_lock); intf->proc_dir = NULL; mutex_lock(&smi_watchers_mutex); @@ -2717,11 +2817,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, get_guid(intf); if ((intf->ipmi_version_major > 1) - || ((intf->ipmi_version_major == 1) - && (intf->ipmi_version_minor >= 5))) - { - /* Start scanning the channels to see what is - available. */ + || ((intf->ipmi_version_major == 1) + && (intf->ipmi_version_minor >= 5))) { + /* + * Start scanning the channels to see what is + * available. + */ intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); @@ -2769,6 +2870,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, return rv; } +EXPORT_SYMBOL(ipmi_register_smi); static void cleanup_smi_msgs(ipmi_smi_t intf) { @@ -2803,8 +2905,10 @@ int ipmi_unregister_smi(ipmi_smi_t intf) remove_proc_entries(intf); - /* Call all the watcher interfaces to tell them that - an interface is gone. */ + /* + * Call all the watcher interfaces to tell them that + * an interface is gone. + */ list_for_each_entry(w, &smi_watchers, link) w->smi_gone(intf_num); mutex_unlock(&smi_watchers_mutex); @@ -2812,22 +2916,21 @@ int ipmi_unregister_smi(ipmi_smi_t intf) kref_put(&intf->refcount, intf_free); return 0; } +EXPORT_SYMBOL(ipmi_unregister_smi); static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_ipmb_addr ipmb_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; - - /* This is 11, not 10, because the response must contain a - * completion code. */ + /* + * This is 11, not 10, because the response must contain a + * completion code. + */ if (msg->rsp_size < 11) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_ipmb_responses); return 0; } @@ -2841,37 +2944,38 @@ static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, ipmb_addr.channel = msg->rsp[3] & 0x0f; ipmb_addr.lun = msg->rsp[7] & 3; - /* It's a response from a remote entity. Look up the sequence - number and handle the response. */ + /* + * It's a response from a remote entity. Look up the sequence + * number and handle the response. + */ if (intf_find_seq(intf, msg->rsp[7] >> 2, msg->rsp[3] & 0x0f, msg->rsp[8], (msg->rsp[4] >> 2) & (~1), (struct ipmi_addr *) &(ipmb_addr), - &recv_msg)) - { - /* We were unable to find the sequence number, - so just nuke the message. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + &recv_msg)) { + /* + * We were unable to find the sequence number, + * so just nuke the message. + */ + ipmi_inc_stat(intf, unhandled_ipmb_responses); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[9]), msg->rsp_size - 9); - /* THe other fields matched, so no need to set them, except - for netfn, which needs to be the response that was - returned, not the request value. */ + /* + * The other fields matched, so no need to set them, except + * for netfn, which needs to be the response that was + * returned, not the request value. + */ recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 10; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_ipmb_responses); deliver_response(recv_msg); return 0; @@ -2888,14 +2992,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ipmi_user_t user = NULL; struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; struct ipmi_smi_handlers *handlers; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_commands); return 0; } @@ -2919,19 +3020,17 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, if (user == NULL) { /* We didn't find a user, deliver an error response. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_commands); msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); msg->data[1] = IPMI_SEND_MSG_CMD; msg->data[2] = msg->rsp[3]; msg->data[3] = msg->rsp[6]; - msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); + msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; - /* rqseq/lun */ - msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); + /* rqseq/lun */ + msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE; msg->data[10] = ipmb_checksum(&(msg->data[6]), 4); @@ -2950,23 +3049,25 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, handlers = intf->handlers; if (handlers) { handlers->sender(intf->send_info, msg, 0); - /* We used the message, so return the value - that causes it to not be freed or - queued. */ + /* + * We used the message, so return the value + * that causes it to not be freed or + * queued. + */ rv = -1; } rcu_read_unlock(); } else { /* Deliver the message to the user. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_commands); recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; kref_put(&user->refcount, free_user); } else { @@ -2977,8 +3078,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ipmb_addr->lun = msg->rsp[7] & 3; ipmb_addr->channel = msg->rsp[3] & 0xf; - /* Extract the rest of the message information - from the IPMB header.*/ + /* + * Extract the rest of the message information + * from the IPMB header. + */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[7] >> 2; @@ -2986,8 +3089,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, recv_msg->msg.cmd = msg->rsp[8]; recv_msg->msg.data = recv_msg->msg_data; - /* We chop off 10, not 9 bytes because the checksum - at the end also needs to be removed. */ + /* + * We chop off 10, not 9 bytes because the checksum + * at the end also needs to be removed. + */ recv_msg->msg.data_len = msg->rsp_size - 10; memcpy(recv_msg->msg_data, &(msg->rsp[9]), @@ -3004,16 +3109,15 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, { struct ipmi_lan_addr lan_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; - /* This is 13, not 12, because the response must contain a - * completion code. */ + /* + * This is 13, not 12, because the response must contain a + * completion code. + */ if (msg->rsp_size < 13) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_lan_responses); return 0; } @@ -3030,37 +3134,38 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, lan_addr.privilege = msg->rsp[3] >> 4; lan_addr.lun = msg->rsp[9] & 3; - /* It's a response from a remote entity. Look up the sequence - number and handle the response. */ + /* + * It's a response from a remote entity. Look up the sequence + * number and handle the response. + */ if (intf_find_seq(intf, msg->rsp[9] >> 2, msg->rsp[3] & 0x0f, msg->rsp[10], (msg->rsp[6] >> 2) & (~1), (struct ipmi_addr *) &(lan_addr), - &recv_msg)) - { - /* We were unable to find the sequence number, - so just nuke the message. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + &recv_msg)) { + /* + * We were unable to find the sequence number, + * so just nuke the message. + */ + ipmi_inc_stat(intf, unhandled_lan_responses); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[11]), msg->rsp_size - 11); - /* The other fields matched, so no need to set them, except - for netfn, which needs to be the response that was - returned, not the request value. */ + /* + * The other fields matched, so no need to set them, except + * for netfn, which needs to be the response that was + * returned, not the request value. + */ recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 12; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_lan_responses); deliver_response(recv_msg); return 0; @@ -3077,13 +3182,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, ipmi_user_t user = NULL; struct ipmi_lan_addr *lan_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_commands); return 0; } @@ -3107,23 +3209,23 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, if (user == NULL) { /* We didn't find a user, just give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_commands); - rv = 0; /* Don't do anything with these messages, just - allow them to be freed. */ + /* + * Don't do anything with these messages, just allow + * them to be freed. + */ + rv = 0; } else { /* Deliver the message to the user. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_commands); recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling later. + */ rv = 1; kref_put(&user->refcount, free_user); } else { @@ -3137,8 +3239,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, lan_addr->channel = msg->rsp[3] & 0xf; lan_addr->privilege = msg->rsp[3] >> 4; - /* Extract the rest of the message information - from the IPMB header.*/ + /* + * Extract the rest of the message information + * from the IPMB header. + */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[9] >> 2; @@ -3146,8 +3250,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, recv_msg->msg.cmd = msg->rsp[10]; recv_msg->msg.data = recv_msg->msg_data; - /* We chop off 12, not 11 bytes because the checksum - at the end also needs to be removed. */ + /* + * We chop off 12, not 11 bytes because the checksum + * at the end also needs to be removed. + */ recv_msg->msg.data_len = msg->rsp_size - 12; memcpy(recv_msg->msg_data, &(msg->rsp[11]), @@ -3163,7 +3269,7 @@ static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, struct ipmi_smi_msg *msg) { struct ipmi_system_interface_addr *smi_addr; - + recv_msg->msgid = 0; smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr); smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; @@ -3189,9 +3295,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, if (msg->rsp_size < 19) { /* Message is too small to be an IPMB event. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_events++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_events); return 0; } @@ -3204,12 +3308,12 @@ static int handle_read_event_rsp(ipmi_smi_t intf, spin_lock_irqsave(&intf->events_lock, flags); - spin_lock(&intf->counter_lock); - intf->events++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, events); - /* Allocate and fill in one message for every user that is getting - events. */ + /* + * Allocate and fill in one message for every user that is + * getting events. + */ rcu_read_lock(); list_for_each_entry_rcu(user, &intf->users, link) { if (!user->gets_events) @@ -3223,9 +3327,11 @@ static int handle_read_event_rsp(ipmi_smi_t intf, list_del(&recv_msg->link); ipmi_free_recv_msg(recv_msg); } - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; goto out; } @@ -3246,13 +3352,17 @@ static int handle_read_event_rsp(ipmi_smi_t intf, deliver_response(recv_msg); } } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) { - /* No one to receive the message, put it in queue if there's - not already too many things in the queue. */ + /* + * No one to receive the message, put it in queue if there's + * not already too many things in the queue. + */ recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; goto out; } @@ -3260,11 +3370,14 @@ static int handle_read_event_rsp(ipmi_smi_t intf, copy_event_into_recv_msg(recv_msg, msg); list_add_tail(&(recv_msg->link), &(intf->waiting_events)); intf->waiting_events_count++; - } else { - /* There's too many things in the queue, discard this - message. */ - printk(KERN_WARNING PFX "Event queue full, discarding an" - " incoming event\n"); + } else if (!intf->event_msg_printed) { + /* + * There's too many things in the queue, discard this + * message. + */ + printk(KERN_WARNING PFX "Event queue full, discarding" + " incoming events\n"); + intf->event_msg_printed = 1; } out: @@ -3277,16 +3390,15 @@ static int handle_bmc_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg; - unsigned long flags; struct ipmi_user *user; recv_msg = (struct ipmi_recv_msg *) msg->user_data; - if (recv_msg == NULL) - { - printk(KERN_WARNING"IPMI message received with no owner. This\n" - "could be because of a malformed message, or\n" - "because of a hardware error. Contact your\n" - "hardware vender for assistance\n"); + if (recv_msg == NULL) { + printk(KERN_WARNING + "IPMI message received with no owner. This\n" + "could be because of a malformed message, or\n" + "because of a hardware error. Contact your\n" + "hardware vender for assistance\n"); return 0; } @@ -3294,16 +3406,12 @@ static int handle_bmc_rsp(ipmi_smi_t intf, /* Make sure the user still exists. */ if (user && !user->valid) { /* The user for the message went away, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_local_responses); ipmi_free_recv_msg(recv_msg); } else { struct ipmi_system_interface_addr *smi_addr; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_local_responses); recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; recv_msg->msgid = msg->msgid; smi_addr = ((struct ipmi_system_interface_addr *) @@ -3324,9 +3432,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf, return 0; } -/* Handle a new message. Return 1 if the message should be requeued, - 0 if the message should be freed, or -1 if the message should not - be freed or requeued. */ +/* + * Handle a new message. Return 1 if the message should be requeued, + * 0 if the message should be freed, or -1 if the message should not + * be freed or requeued. + */ static int handle_new_recv_msg(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { @@ -3351,10 +3461,12 @@ static int handle_new_recv_msg(ipmi_smi_t intf, msg->rsp[1] = msg->data[1]; msg->rsp[2] = IPMI_ERR_UNSPECIFIED; msg->rsp_size = 3; - } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */ - || (msg->rsp[1] != msg->data[1])) /* Command */ - { - /* The response is not even marginally correct. */ + } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1)) + || (msg->rsp[1] != msg->data[1])) { + /* + * The NetFN and Command in the response is not even + * marginally correct. + */ printk(KERN_WARNING PFX "BMC returned incorrect response," " expected netfn %x cmd %x, got netfn %x cmd %x\n", (msg->data[0] >> 2) | 1, msg->data[1], @@ -3369,10 +3481,11 @@ static int handle_new_recv_msg(ipmi_smi_t intf, if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data != NULL)) - { - /* It's a response to a response we sent. For this we - deliver a send message response to the user. */ + && (msg->user_data != NULL)) { + /* + * It's a response to a response we sent. For this we + * deliver a send message response to the user. + */ struct ipmi_recv_msg *recv_msg = msg->user_data; requeue = 0; @@ -3398,8 +3511,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf, recv_msg->msg_data[0] = msg->rsp[2]; deliver_response(recv_msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_GET_MSG_CMD)) - { + && (msg->rsp[1] == IPMI_GET_MSG_CMD)) { /* It's from the receive queue. */ chan = msg->rsp[3] & 0xf; if (chan >= IPMI_MAX_CHANNELS) { @@ -3411,12 +3523,16 @@ static int handle_new_recv_msg(ipmi_smi_t intf, switch (intf->channels[chan].medium) { case IPMI_CHANNEL_MEDIUM_IPMB: if (msg->rsp[4] & 0x04) { - /* It's a response, so find the - requesting message and send it up. */ + /* + * It's a response, so find the + * requesting message and send it up. + */ requeue = handle_ipmb_get_msg_rsp(intf, msg); } else { - /* It's a command to the SMS from some other - entity. Handle that. */ + /* + * It's a command to the SMS from some other + * entity. Handle that. + */ requeue = handle_ipmb_get_msg_cmd(intf, msg); } break; @@ -3424,25 +3540,30 @@ static int handle_new_recv_msg(ipmi_smi_t intf, case IPMI_CHANNEL_MEDIUM_8023LAN: case IPMI_CHANNEL_MEDIUM_ASYNC: if (msg->rsp[6] & 0x04) { - /* It's a response, so find the - requesting message and send it up. */ + /* + * It's a response, so find the + * requesting message and send it up. + */ requeue = handle_lan_get_msg_rsp(intf, msg); } else { - /* It's a command to the SMS from some other - entity. Handle that. */ + /* + * It's a command to the SMS from some other + * entity. Handle that. + */ requeue = handle_lan_get_msg_cmd(intf, msg); } break; default: - /* We don't handle the channel type, so just - * free the message. */ + /* + * We don't handle the channel type, so just + * free the message. + */ requeue = 0; } } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) - { + && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) { /* It's an asyncronous event. */ requeue = handle_read_event_rsp(intf, msg); } else { @@ -3458,71 +3579,82 @@ static int handle_new_recv_msg(ipmi_smi_t intf, void ipmi_smi_msg_received(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { - unsigned long flags; + unsigned long flags = 0; /* keep us warning-free. */ int rv; + int run_to_completion; if ((msg->data_size >= 2) && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) && (msg->data[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data == NULL)) - { - /* This is the local response to a command send, start - the timer for these. The user_data will not be - NULL if this is a response send, and we will let - response sends just go through. */ - - /* Check for errors, if we get certain errors (ones - that mean basically we can try again later), we - ignore them and start the timer. Otherwise we - report the error immediately. */ + && (msg->user_data == NULL)) { + /* + * This is the local response to a command send, start + * the timer for these. The user_data will not be + * NULL if this is a response send, and we will let + * response sends just go through. + */ + + /* + * Check for errors, if we get certain errors (ones + * that mean basically we can try again later), we + * ignore them and start the timer. Otherwise we + * report the error immediately. + */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) && (msg->rsp[2] != IPMI_BUS_ERR) - && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) - { + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int chan = msg->rsp[3] & 0xf; /* Got an error sending the message, handle it. */ - spin_lock_irqsave(&intf->counter_lock, flags); if (chan >= IPMI_MAX_CHANNELS) ; /* This shouldn't happen */ else if ((intf->channels[chan].medium == IPMI_CHANNEL_MEDIUM_8023LAN) || (intf->channels[chan].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) - intf->sent_lan_command_errs++; + ipmi_inc_stat(intf, sent_lan_command_errs); else - intf->sent_ipmb_command_errs++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_ipmb_command_errs); intf_err_seq(intf, msg->msgid, msg->rsp[2]); - } else { + } else /* The message was sent, start the timer. */ intf_start_seq_timer(intf, msg->msgid); - } ipmi_free_smi_msg(msg); goto out; } - /* To preserve message order, if the list is not empty, we - tack this message onto the end of the list. */ - spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + /* + * To preserve message order, if the list is not empty, we + * tack this message onto the end of the list. + */ + run_to_completion = intf->run_to_completion; + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); if (!list_empty(&intf->waiting_msgs)) { list_add_tail(&msg->link, &intf->waiting_msgs); - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); goto out; } - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); - + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + rv = handle_new_recv_msg(intf, msg); if (rv > 0) { - /* Could not handle the message now, just add it to a - list to handle later. */ - spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + /* + * Could not handle the message now, just add it to a + * list to handle later. + */ + run_to_completion = intf->run_to_completion; + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); list_add_tail(&msg->link, &intf->waiting_msgs); - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); } else if (rv == 0) { ipmi_free_smi_msg(msg); } @@ -3530,6 +3662,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, out: return; } +EXPORT_SYMBOL(ipmi_smi_msg_received); void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) { @@ -3544,7 +3677,7 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) } rcu_read_unlock(); } - +EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); static struct ipmi_smi_msg * smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, @@ -3552,14 +3685,16 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, { struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); if (!smi_msg) - /* If we can't allocate the message, then just return, we - get 4 retries, so this should be ok. */ + /* + * If we can't allocate the message, then just return, we + * get 4 retries, so this should be ok. + */ return NULL; memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); - + #ifdef DEBUG_MSGING { int m; @@ -3594,28 +3729,26 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ent->inuse = 0; msg = ent->recv_msg; list_add_tail(&msg->link, timeouts); - spin_lock(&intf->counter_lock); if (ent->broadcast) - intf->timed_out_ipmb_broadcasts++; + ipmi_inc_stat(intf, timed_out_ipmb_broadcasts); else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) - intf->timed_out_lan_commands++; + ipmi_inc_stat(intf, timed_out_lan_commands); else - intf->timed_out_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, timed_out_ipmb_commands); } else { struct ipmi_smi_msg *smi_msg; /* More retries, send again. */ - /* Start with the max timer, set to normal - timer after the message is sent. */ + /* + * Start with the max timer, set to normal timer after + * the message is sent. + */ ent->timeout = MAX_MSG_TIMEOUT; ent->retries_left--; - spin_lock(&intf->counter_lock); if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) - intf->retransmitted_lan_commands++; + ipmi_inc_stat(intf, retransmitted_lan_commands); else - intf->retransmitted_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, retransmitted_ipmb_commands); smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot, ent->seqid); @@ -3624,11 +3757,13 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, spin_unlock_irqrestore(&intf->seq_lock, *flags); - /* Send the new message. We send with a zero - * priority. It timed out, I doubt time is - * that critical now, and high priority - * messages are really only for messages to the - * local MC, which don't get resent. */ + /* + * Send the new message. We send with a zero + * priority. It timed out, I doubt time is that + * critical now, and high priority messages are really + * only for messages to the local MC, which don't get + * resent. + */ handlers = intf->handlers; if (handlers) intf->handlers->sender(intf->send_info, @@ -3659,16 +3794,20 @@ static void ipmi_timeout_handler(long timeout_period) list_del(&smi_msg->link); ipmi_free_smi_msg(smi_msg); } else { - /* To preserve message order, quit if we - can't handle a message. */ + /* + * To preserve message order, quit if we + * can't handle a message. + */ break; } } spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); - /* Go through the seq table and find any messages that - have timed out, putting them in the timeouts - list. */ + /* + * Go through the seq table and find any messages that + * have timed out, putting them in the timeouts + * list. + */ INIT_LIST_HEAD(&timeouts); spin_lock_irqsave(&intf->seq_lock, flags); for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) @@ -3694,8 +3833,7 @@ static void ipmi_timeout_handler(long timeout_period) intf->auto_maintenance_timeout -= timeout_period; if (!intf->maintenance_mode - && (intf->auto_maintenance_timeout <= 0)) - { + && (intf->auto_maintenance_timeout <= 0)) { intf->maintenance_mode_enable = 0; maintenance_mode_update(intf); } @@ -3713,8 +3851,10 @@ static void ipmi_request_event(void) struct ipmi_smi_handlers *handlers; rcu_read_lock(); - /* Called from the timer, no need to check if handlers is - * valid. */ + /* + * Called from the timer, no need to check if handlers is + * valid. + */ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { /* No event requests when in maintenance mode. */ if (intf->maintenance_mode_enable) @@ -3735,10 +3875,12 @@ static struct timer_list ipmi_timer; /* How many jiffies does it take to get to the timeout time. */ #define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000) -/* Request events from the queue every second (this is the number of - IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the - future, IPMI will add a way to know immediately if an event is in - the queue and this silliness can go away. */ +/* + * Request events from the queue every second (this is the number of + * IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the + * future, IPMI will add a way to know immediately if an event is in + * the queue and this silliness can go away. + */ #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) static atomic_t stop_operation; @@ -3782,6 +3924,7 @@ struct ipmi_smi_msg *ipmi_alloc_smi_msg(void) } return rv; } +EXPORT_SYMBOL(ipmi_alloc_smi_msg); static void free_recv_msg(struct ipmi_recv_msg *msg) { @@ -3789,7 +3932,7 @@ static void free_recv_msg(struct ipmi_recv_msg *msg) kfree(msg); } -struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) +static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) { struct ipmi_recv_msg *rv; @@ -3808,6 +3951,7 @@ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) kref_put(&msg->user->refcount, free_user); msg->done(msg); } +EXPORT_SYMBOL(ipmi_free_recv_msg); #ifdef CONFIG_IPMI_PANIC_EVENT @@ -3825,8 +3969,7 @@ static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE) && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD) - && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) - { + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get event receiver command, save it. */ intf->event_receiver = msg->msg.data[1]; intf->event_receiver_lun = msg->msg.data[2] & 0x3; @@ -3838,10 +3981,11 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD) - && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) - { - /* A get device id command, save if we are an event - receiver or generator. */ + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { + /* + * A get device id command, save if we are an event + * receiver or generator. + */ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1; intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } @@ -3874,8 +4018,10 @@ static void send_panic_events(char *str) data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */ data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */ - /* Put a few breadcrumbs in. Hopefully later we can add more things - to make the panic events more useful. */ + /* + * Put a few breadcrumbs in. Hopefully later we can add more things + * to make the panic events more useful. + */ if (str) { data[3] = str[0]; data[6] = str[1]; @@ -3891,6 +4037,7 @@ static void send_panic_events(char *str) /* Interface is not ready. */ continue; + intf->run_to_completion = 1; /* Send the event announcing the panic. */ intf->handlers->set_run_to_completion(intf->send_info, 1); i_ipmi_request(NULL, @@ -3908,9 +4055,11 @@ static void send_panic_events(char *str) } #ifdef CONFIG_IPMI_PANIC_STRING - /* On every interface, dump a bunch of OEM event holding the - string. */ - if (!str) + /* + * On every interface, dump a bunch of OEM event holding the + * string. + */ + if (!str) return; /* For every registered interface, send the event. */ @@ -3931,11 +4080,13 @@ static void send_panic_events(char *str) */ smp_rmb(); - /* First job here is to figure out where to send the - OEM events. There's no way in IPMI to send OEM - events using an event send command, so we have to - find the SEL to put them in and stick them in - there. */ + /* + * First job here is to figure out where to send the + * OEM events. There's no way in IPMI to send OEM + * events using an event send command, so we have to + * find the SEL to put them in and stick them in + * there. + */ /* Get capabilities from the get device id. */ intf->local_sel_device = 0; @@ -3983,24 +4134,29 @@ static void send_panic_events(char *str) } intf->null_user_handler = NULL; - /* Validate the event receiver. The low bit must not - be 1 (it must be a valid IPMB address), it cannot - be zero, and it must not be my address. */ - if (((intf->event_receiver & 1) == 0) + /* + * Validate the event receiver. The low bit must not + * be 1 (it must be a valid IPMB address), it cannot + * be zero, and it must not be my address. + */ + if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) - && (intf->event_receiver != intf->channels[0].address)) - { - /* The event receiver is valid, send an IPMB - message. */ + && (intf->event_receiver != intf->channels[0].address)) { + /* + * The event receiver is valid, send an IPMB + * message. + */ ipmb = (struct ipmi_ipmb_addr *) &addr; ipmb->addr_type = IPMI_IPMB_ADDR_TYPE; ipmb->channel = 0; /* FIXME - is this right? */ ipmb->lun = intf->event_receiver_lun; ipmb->slave_addr = intf->event_receiver; } else if (intf->local_sel_device) { - /* The event receiver was not valid (or was - me), but I am an SEL device, just dump it - in my SEL. */ + /* + * The event receiver was not valid (or was + * me), but I am an SEL device, just dump it + * in my SEL. + */ si = (struct ipmi_system_interface_addr *) &addr; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->channel = IPMI_BMC_CHANNEL; @@ -4008,7 +4164,6 @@ static void send_panic_events(char *str) } else continue; /* No where to send the event. */ - msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */ msg.cmd = IPMI_ADD_SEL_ENTRY_CMD; msg.data = data; @@ -4025,8 +4180,10 @@ static void send_panic_events(char *str) data[2] = 0xf0; /* OEM event without timestamp. */ data[3] = intf->channels[0].address; data[4] = j++; /* sequence # */ - /* Always give 11 bytes, so strncpy will fill - it with zeroes for me. */ + /* + * Always give 11 bytes, so strncpy will fill + * it with zeroes for me. + */ strncpy(data+5, p, 11); p += size; @@ -4043,7 +4200,7 @@ static void send_panic_events(char *str) intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } - } + } #endif /* CONFIG_IPMI_PANIC_STRING */ } #endif /* CONFIG_IPMI_PANIC_EVENT */ @@ -4052,7 +4209,7 @@ static int has_panicked; static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) + void *ptr) { ipmi_smi_t intf; @@ -4066,6 +4223,7 @@ static int panic_event(struct notifier_block *this, /* Interface is not ready. */ continue; + intf->run_to_completion = 1; intf->handlers->set_run_to_completion(intf->send_info, 1); } @@ -4133,11 +4291,16 @@ static __exit void cleanup_ipmi(void) atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); - /* This can't be called if any interfaces exist, so no worry about - shutting down the interfaces. */ + /* + * This can't be called if any interfaces exist, so no worry + * about shutting down the interfaces. + */ - /* Tell the timer to stop, then wait for it to stop. This avoids - problems with race conditions removing the timer here. */ + /* + * Tell the timer to stop, then wait for it to stop. This + * avoids problems with race conditions removing the timer + * here. + */ atomic_inc(&stop_operation); del_timer_sync(&ipmi_timer); @@ -4164,31 +4327,6 @@ module_exit(cleanup_ipmi); module_init(ipmi_init_msghandler_mod); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); -MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface."); +MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI" + " interface."); MODULE_VERSION(IPMI_DRIVER_VERSION); - -EXPORT_SYMBOL(ipmi_create_user); -EXPORT_SYMBOL(ipmi_destroy_user); -EXPORT_SYMBOL(ipmi_get_version); -EXPORT_SYMBOL(ipmi_request_settime); -EXPORT_SYMBOL(ipmi_request_supply_msgs); -EXPORT_SYMBOL(ipmi_poll_interface); -EXPORT_SYMBOL(ipmi_register_smi); -EXPORT_SYMBOL(ipmi_unregister_smi); -EXPORT_SYMBOL(ipmi_register_for_cmd); -EXPORT_SYMBOL(ipmi_unregister_for_cmd); -EXPORT_SYMBOL(ipmi_smi_msg_received); -EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); -EXPORT_SYMBOL(ipmi_alloc_smi_msg); -EXPORT_SYMBOL(ipmi_addr_length); -EXPORT_SYMBOL(ipmi_validate_addr); -EXPORT_SYMBOL(ipmi_set_gets_events); -EXPORT_SYMBOL(ipmi_smi_watcher_register); -EXPORT_SYMBOL(ipmi_smi_watcher_unregister); -EXPORT_SYMBOL(ipmi_set_my_address); -EXPORT_SYMBOL(ipmi_get_my_address); -EXPORT_SYMBOL(ipmi_set_my_LUN); -EXPORT_SYMBOL(ipmi_get_my_LUN); -EXPORT_SYMBOL(ipmi_smi_add_proc_entry); -EXPORT_SYMBOL(ipmi_user_set_run_to_completion); -EXPORT_SYMBOL(ipmi_free_recv_msg); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index b86186de7f07..a261bd735dfb 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -87,7 +87,10 @@ MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " /* parameter definition to allow user to flag power cycle */ module_param(poweroff_powercycle, int, 0644); -MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); +MODULE_PARM_DESC(poweroff_powercycle, + " Set to non-zero to enable power cycle instead of power" + " down. Power cycle is contingent on hardware support," + " otherwise it defaults back to power down."); /* Stuff from the get device id command. */ static unsigned int mfg_id; @@ -95,22 +98,25 @@ static unsigned int prod_id; static unsigned char capabilities; static unsigned char ipmi_version; -/* We use our own messages for this operation, we don't let the system - allocate them, since we may be in a panic situation. The whole - thing is single-threaded, anyway, so multiple messages are not - required. */ +/* + * We use our own messages for this operation, we don't let the system + * allocate them, since we may be in a panic situation. The whole + * thing is single-threaded, anyway, so multiple messages are not + * required. + */ +static atomic_t dummy_count = ATOMIC_INIT(0); static void dummy_smi_free(struct ipmi_smi_msg *msg) { + atomic_dec(&dummy_count); } static void dummy_recv_free(struct ipmi_recv_msg *msg) { + atomic_dec(&dummy_count); } -static struct ipmi_smi_msg halt_smi_msg = -{ +static struct ipmi_smi_msg halt_smi_msg = { .done = dummy_smi_free }; -static struct ipmi_recv_msg halt_recv_msg = -{ +static struct ipmi_recv_msg halt_recv_msg = { .done = dummy_recv_free }; @@ -127,8 +133,7 @@ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) complete(comp); } -static struct ipmi_user_hndl ipmi_poweroff_handler = -{ +static struct ipmi_user_hndl ipmi_poweroff_handler = { .ipmi_recv_hndl = receive_handler }; @@ -152,17 +157,28 @@ static int ipmi_request_wait_for_response(ipmi_user_t user, return halt_recv_msg.msg.data[0]; } -/* We are in run-to-completion mode, no completion is desired. */ +/* Wait for message to complete, spinning. */ static int ipmi_request_in_rc_mode(ipmi_user_t user, struct ipmi_addr *addr, struct kernel_ipmi_msg *send_msg) { int rv; + atomic_set(&dummy_count, 2); rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, &halt_smi_msg, &halt_recv_msg, 0); - if (rv) + if (rv) { + atomic_set(&dummy_count, 0); return rv; + } + + /* + * Spin until our message is done. + */ + while (atomic_read(&dummy_count) > 0) { + ipmi_poll_interface(user); + cpu_relax(); + } return halt_recv_msg.msg.data[0]; } @@ -184,47 +200,47 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user, static void (*atca_oem_poweroff_hook)(ipmi_user_t user); -static void pps_poweroff_atca (ipmi_user_t user) +static void pps_poweroff_atca(ipmi_user_t user) { - struct ipmi_system_interface_addr smi_addr; - struct kernel_ipmi_msg send_msg; - int rv; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; - - printk(KERN_INFO PFX "PPS powerdown hook used"); - - send_msg.netfn = IPMI_NETFN_OEM; - send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; - send_msg.data = IPMI_ATCA_PPS_IANA; - send_msg.data_len = 3; - rv = ipmi_request_in_rc_mode(user, - (struct ipmi_addr *) &smi_addr, - &send_msg); - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { - printk(KERN_ERR PFX "Unable to send ATCA ," - " IPMI error 0x%x\n", rv); - } + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "PPS powerdown hook used"); + + send_msg.netfn = IPMI_NETFN_OEM; + send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; + send_msg.data = IPMI_ATCA_PPS_IANA; + send_msg.data_len = 3; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + printk(KERN_ERR PFX "Unable to send ATCA ," + " IPMI error 0x%x\n", rv); + } return; } -static int ipmi_atca_detect (ipmi_user_t user) +static int ipmi_atca_detect(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; /* * Use get address info to check and see if we are ATCA @@ -238,28 +254,30 @@ static int ipmi_atca_detect (ipmi_user_t user) (struct ipmi_addr *) &smi_addr, &send_msg); - printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); - if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) - && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { - printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n"); + printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", + mfg_id, prod_id); + if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) + && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { + printk(KERN_INFO PFX + "Installing Pigeon Point Systems Poweroff Hook\n"); atca_oem_poweroff_hook = pps_poweroff_atca; } return !rv; } -static void ipmi_poweroff_atca (ipmi_user_t user) +static void ipmi_poweroff_atca(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[4]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; printk(KERN_INFO PFX "Powering down via ATCA power command\n"); @@ -273,23 +291,24 @@ static void ipmi_poweroff_atca (ipmi_user_t user) data[2] = 0; /* Power Level */ data[3] = 0; /* Don't change saved presets */ send_msg.data = data; - send_msg.data_len = sizeof (data); + send_msg.data_len = sizeof(data); rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); - /** At this point, the system may be shutting down, and most - ** serial drivers (if used) will have interrupts turned off - ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE - ** return code - **/ - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + /* + * At this point, the system may be shutting down, and most + * serial drivers (if used) will have interrupts turned off + * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE + * return code + */ + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { printk(KERN_ERR PFX "Unable to send ATCA powerdown message," " IPMI error 0x%x\n", rv); goto out; } - if(atca_oem_poweroff_hook) - return atca_oem_poweroff_hook(user); + if (atca_oem_poweroff_hook) + atca_oem_poweroff_hook(user); out: return; } @@ -310,13 +329,13 @@ static void ipmi_poweroff_atca (ipmi_user_t user) #define IPMI_CPI1_PRODUCT_ID 0x000157 #define IPMI_CPI1_MANUFACTURER_ID 0x0108 -static int ipmi_cpi1_detect (ipmi_user_t user) +static int ipmi_cpi1_detect(ipmi_user_t user) { return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID) && (prod_id == IPMI_CPI1_PRODUCT_ID)); } -static void ipmi_poweroff_cpi1 (ipmi_user_t user) +static void ipmi_poweroff_cpi1(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct ipmi_ipmb_addr ipmb_addr; @@ -328,12 +347,12 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) unsigned char aer_addr; unsigned char aer_lun; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; printk(KERN_INFO PFX "Powering down via CPI1 power command\n"); @@ -425,7 +444,7 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) */ #define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} -static int ipmi_dell_chassis_detect (ipmi_user_t user) +static int ipmi_dell_chassis_detect(ipmi_user_t user) { const char ipmi_version_major = ipmi_version & 0xF; const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; @@ -444,25 +463,25 @@ static int ipmi_dell_chassis_detect (ipmi_user_t user) #define IPMI_NETFN_CHASSIS_REQUEST 0 #define IPMI_CHASSIS_CONTROL_CMD 0x02 -static int ipmi_chassis_detect (ipmi_user_t user) +static int ipmi_chassis_detect(ipmi_user_t user) { /* Chassis support, use it. */ return (capabilities & 0x80); } -static void ipmi_poweroff_chassis (ipmi_user_t user) +static void ipmi_poweroff_chassis(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; powercyclefailed: printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", @@ -525,15 +544,13 @@ static struct poweroff_function poweroff_functions[] = { /* Called on a powerdown request. */ -static void ipmi_poweroff_function (void) +static void ipmi_poweroff_function(void) { if (!ready) return; /* Use run-to-completion mode, since interrupts may be off. */ - ipmi_user_set_run_to_completion(ipmi_user, 1); specific_poweroff_func(ipmi_user); - ipmi_user_set_run_to_completion(ipmi_user, 0); } /* Wait for an IPMI interface to be installed, the first one installed @@ -561,13 +578,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device) ipmi_ifnum = if_num; - /* - * Do a get device ide and store some results, since this is + /* + * Do a get device ide and store some results, since this is * used by several functions. - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; send_msg.netfn = IPMI_NETFN_APP_REQUEST; send_msg.cmd = IPMI_GET_DEVICE_ID_CMD; @@ -632,8 +649,7 @@ static void ipmi_po_smi_gone(int if_num) pm_power_off = old_poweroff_func; } -static struct ipmi_smi_watcher smi_watcher = -{ +static struct ipmi_smi_watcher smi_watcher = { .owner = THIS_MODULE, .new_smi = ipmi_po_new_smi, .smi_gone = ipmi_po_smi_gone @@ -675,12 +691,12 @@ static struct ctl_table_header *ipmi_table_header; /* * Startup and shutdown functions. */ -static int ipmi_poweroff_init (void) +static int ipmi_poweroff_init(void) { int rv; - printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -" - " IPMI Powerdown via sys_reboot.\n"); + printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -" + " IPMI Powerdown via sys_reboot.\n"); if (poweroff_powercycle) printk(KERN_INFO PFX "Power cycle is enabled.\n"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4f560d0bb808..5a5455585c1d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -80,7 +80,7 @@ #define SI_USEC_PER_JIFFY (1000000/HZ) #define SI_TIMEOUT_JIFFIES (SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY) #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a - short timeout */ + short timeout */ /* Bit for BMC global enables. */ #define IPMI_BMC_RCV_MSG_INTR 0x01 @@ -114,14 +114,61 @@ static char *si_to_str[] = { "kcs", "smic", "bt" }; #define DEVICE_NAME "ipmi_si" -static struct device_driver ipmi_driver = -{ +static struct device_driver ipmi_driver = { .name = DEVICE_NAME, .bus = &platform_bus_type }; -struct smi_info -{ + +/* + * Indexes into stats[] in smi_info below. + */ +enum si_stat_indexes { + /* + * Number of times the driver requested a timer while an operation + * was in progress. + */ + SI_STAT_short_timeouts = 0, + + /* + * Number of times the driver requested a timer while nothing was in + * progress. + */ + SI_STAT_long_timeouts, + + /* Number of times the interface was idle while being polled. */ + SI_STAT_idles, + + /* Number of interrupts the driver handled. */ + SI_STAT_interrupts, + + /* Number of time the driver got an ATTN from the hardware. */ + SI_STAT_attentions, + + /* Number of times the driver requested flags from the hardware. */ + SI_STAT_flag_fetches, + + /* Number of times the hardware didn't follow the state machine. */ + SI_STAT_hosed_count, + + /* Number of completed messages. */ + SI_STAT_complete_transactions, + + /* Number of IPMI events received from the hardware. */ + SI_STAT_events, + + /* Number of watchdog pretimeouts. */ + SI_STAT_watchdog_pretimeouts, + + /* Number of asyncronous messages received. */ + SI_STAT_incoming_messages, + + + /* This *must* remain last, add new values above this. */ + SI_NUM_STATS +}; + +struct smi_info { int intf_num; ipmi_smi_t intf; struct si_sm_data *si_sm; @@ -134,8 +181,10 @@ struct smi_info struct ipmi_smi_msg *curr_msg; enum si_intf_state si_state; - /* Used to handle the various types of I/O that can occur with - IPMI */ + /* + * Used to handle the various types of I/O that can occur with + * IPMI + */ struct si_sm_io io; int (*io_setup)(struct smi_info *info); void (*io_cleanup)(struct smi_info *info); @@ -146,15 +195,18 @@ struct smi_info void (*addr_source_cleanup)(struct smi_info *info); void *addr_source_data; - /* Per-OEM handler, called from handle_flags(). - Returns 1 when handle_flags() needs to be re-run - or 0 indicating it set si_state itself. - */ + /* + * Per-OEM handler, called from handle_flags(). Returns 1 + * when handle_flags() needs to be re-run or 0 indicating it + * set si_state itself. + */ int (*oem_data_avail_handler)(struct smi_info *smi_info); - /* Flags from the last GET_MSG_FLAGS command, used when an ATTN - is set to hold the flags until we are done handling everything - from the flags. */ + /* + * Flags from the last GET_MSG_FLAGS command, used when an ATTN + * is set to hold the flags until we are done handling everything + * from the flags. + */ #define RECEIVE_MSG_AVAIL 0x01 #define EVENT_MSG_BUFFER_FULL 0x02 #define WDT_PRE_TIMEOUT_INT 0x08 @@ -162,25 +214,31 @@ struct smi_info #define OEM1_DATA_AVAIL 0x40 #define OEM2_DATA_AVAIL 0x80 #define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \ - OEM1_DATA_AVAIL | \ - OEM2_DATA_AVAIL) + OEM1_DATA_AVAIL | \ + OEM2_DATA_AVAIL) unsigned char msg_flags; - /* If set to true, this will request events the next time the - state machine is idle. */ + /* + * If set to true, this will request events the next time the + * state machine is idle. + */ atomic_t req_events; - /* If true, run the state machine to completion on every send - call. Generally used after a panic to make sure stuff goes - out. */ + /* + * If true, run the state machine to completion on every send + * call. Generally used after a panic to make sure stuff goes + * out. + */ int run_to_completion; /* The I/O port of an SI interface. */ int port; - /* The space between start addresses of the two ports. For - instance, if the first port is 0xca2 and the spacing is 4, then - the second port is 0xca6. */ + /* + * The space between start addresses of the two ports. For + * instance, if the first port is 0xca2 and the spacing is 4, then + * the second port is 0xca6. + */ unsigned int spacing; /* zero if no irq; */ @@ -195,10 +253,12 @@ struct smi_info /* Used to gracefully stop the timer without race conditions. */ atomic_t stop_operation; - /* The driver will disable interrupts when it gets into a - situation where it cannot handle messages due to lack of - memory. Once that situation clears up, it will re-enable - interrupts. */ + /* + * The driver will disable interrupts when it gets into a + * situation where it cannot handle messages due to lack of + * memory. Once that situation clears up, it will re-enable + * interrupts. + */ int interrupt_disabled; /* From the get device id response... */ @@ -208,33 +268,28 @@ struct smi_info struct device *dev; struct platform_device *pdev; - /* True if we allocated the device, false if it came from - * someplace else (like PCI). */ + /* + * True if we allocated the device, false if it came from + * someplace else (like PCI). + */ int dev_registered; /* Slave address, could be reported from DMI. */ unsigned char slave_addr; /* Counters and things for the proc filesystem. */ - spinlock_t count_lock; - unsigned long short_timeouts; - unsigned long long_timeouts; - unsigned long timeout_restarts; - unsigned long idles; - unsigned long interrupts; - unsigned long attentions; - unsigned long flag_fetches; - unsigned long hosed_count; - unsigned long complete_transactions; - unsigned long events; - unsigned long watchdog_pretimeouts; - unsigned long incoming_messages; - - struct task_struct *thread; + atomic_t stats[SI_NUM_STATS]; + + struct task_struct *thread; struct list_head link; }; +#define smi_inc_stat(smi, stat) \ + atomic_inc(&(smi)->stats[SI_STAT_ ## stat]) +#define smi_get_stat(smi, stat) \ + ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat])) + #define SI_MAX_PARMS 4 static int force_kipmid[SI_MAX_PARMS]; @@ -246,7 +301,7 @@ static int try_smi_init(struct smi_info *smi); static void cleanup_one_si(struct smi_info *to_clean); static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); -static int register_xaction_notifier(struct notifier_block * nb) +static int register_xaction_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(&xaction_notifier_list, nb); } @@ -255,7 +310,7 @@ static void deliver_recv_msg(struct smi_info *smi_info, struct ipmi_smi_msg *msg) { /* Deliver the message to the upper layer with the lock - released. */ + released. */ spin_unlock(&(smi_info->si_lock)); ipmi_smi_msg_received(smi_info->intf, msg); spin_lock(&(smi_info->si_lock)); @@ -287,9 +342,12 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) struct timeval t; #endif - /* No need to save flags, we aleady have interrupts off and we - already hold the SMI lock. */ - spin_lock(&(smi_info->msg_lock)); + /* + * No need to save flags, we aleady have interrupts off and we + * already hold the SMI lock. + */ + if (!smi_info->run_to_completion) + spin_lock(&(smi_info->msg_lock)); /* Pick the high priority queue first. */ if (!list_empty(&(smi_info->hp_xmit_msgs))) { @@ -310,7 +368,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) link); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif err = atomic_notifier_call_chain(&xaction_notifier_list, 0, smi_info); @@ -322,14 +380,14 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) smi_info->si_sm, smi_info->curr_msg->data, smi_info->curr_msg->data_size); - if (err) { + if (err) return_hosed_msg(smi_info, err); - } rv = SI_SM_CALL_WITHOUT_DELAY; } - out: - spin_unlock(&(smi_info->msg_lock)); + out: + if (!smi_info->run_to_completion) + spin_unlock(&(smi_info->msg_lock)); return rv; } @@ -338,8 +396,10 @@ static void start_enable_irq(struct smi_info *smi_info) { unsigned char msg[2]; - /* If we are enabling interrupts, we have to tell the - BMC to use them. */ + /* + * If we are enabling interrupts, we have to tell the + * BMC to use them. + */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; @@ -371,10 +431,12 @@ static void start_clear_flags(struct smi_info *smi_info) smi_info->si_state = SI_CLEARING_FLAGS; } -/* When we have a situtaion where we run out of memory and cannot - allocate messages, we just leave them in the BMC and run the system - polled until we can allocate some memory. Once we have some - memory, we will re-enable the interrupt. */ +/* + * When we have a situtaion where we run out of memory and cannot + * allocate messages, we just leave them in the BMC and run the system + * polled until we can allocate some memory. Once we have some + * memory, we will re-enable the interrupt. + */ static inline void disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { @@ -396,9 +458,7 @@ static void handle_flags(struct smi_info *smi_info) retry: if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) { /* Watchdog pre-timeout */ - spin_lock(&smi_info->count_lock); - smi_info->watchdog_pretimeouts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, watchdog_pretimeouts); start_clear_flags(smi_info); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; @@ -444,12 +504,11 @@ static void handle_flags(struct smi_info *smi_info) smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; } else if (smi_info->msg_flags & OEM_DATA_AVAIL && - smi_info->oem_data_avail_handler) { + smi_info->oem_data_avail_handler) { if (smi_info->oem_data_avail_handler(smi_info)) goto retry; - } else { + } else smi_info->si_state = SI_NORMAL; - } } static void handle_transaction_done(struct smi_info *smi_info) @@ -459,7 +518,7 @@ static void handle_transaction_done(struct smi_info *smi_info) struct timeval t; do_gettimeofday(&t); - printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif switch (smi_info->si_state) { case SI_NORMAL: @@ -472,9 +531,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; deliver_recv_msg(smi_info, msg); @@ -488,12 +549,13 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - /* Error fetching flags, just give up for - now. */ + /* Error fetching flags, just give up for now. */ smi_info->si_state = SI_NORMAL; } else if (len < 4) { - /* Hmm, no flags. That's technically illegal, but - don't use uninitialized data. */ + /* + * Hmm, no flags. That's technically illegal, but + * don't use uninitialized data. + */ smi_info->si_state = SI_NORMAL; } else { smi_info->msg_flags = msg[3]; @@ -530,9 +592,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { @@ -543,14 +607,14 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; handle_flags(smi_info); } else { - spin_lock(&smi_info->count_lock); - smi_info->events++; - spin_unlock(&smi_info->count_lock); - - /* Do this before we deliver the message - because delivering the message releases the - lock and something else can mess with the - state. */ + smi_inc_stat(smi_info, events); + + /* + * Do this before we deliver the message + * because delivering the message releases the + * lock and something else can mess with the + * state. + */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); @@ -566,9 +630,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { @@ -579,14 +645,14 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL; handle_flags(smi_info); } else { - spin_lock(&smi_info->count_lock); - smi_info->incoming_messages++; - spin_unlock(&smi_info->count_lock); - - /* Do this before we deliver the message - because delivering the message releases the - lock and something else can mess with the - state. */ + smi_inc_stat(smi_info, incoming_messages); + + /* + * Do this before we deliver the message + * because delivering the message releases the + * lock and something else can mess with the + * state. + */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); @@ -674,69 +740,70 @@ static void handle_transaction_done(struct smi_info *smi_info) } } -/* Called on timeouts and events. Timeouts should pass the elapsed - time, interrupts should pass in zero. Must be called with - si_lock held and interrupts disabled. */ +/* + * Called on timeouts and events. Timeouts should pass the elapsed + * time, interrupts should pass in zero. Must be called with + * si_lock held and interrupts disabled. + */ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, int time) { enum si_sm_result si_sm_result; restart: - /* There used to be a loop here that waited a little while - (around 25us) before giving up. That turned out to be - pointless, the minimum delays I was seeing were in the 300us - range, which is far too long to wait in an interrupt. So - we just run until the state machine tells us something - happened or it needs a delay. */ + /* + * There used to be a loop here that waited a little while + * (around 25us) before giving up. That turned out to be + * pointless, the minimum delays I was seeing were in the 300us + * range, which is far too long to wait in an interrupt. So + * we just run until the state machine tells us something + * happened or it needs a delay. + */ si_sm_result = smi_info->handlers->event(smi_info->si_sm, time); time = 0; while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY) - { si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - } - if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) - { - spin_lock(&smi_info->count_lock); - smi_info->complete_transactions++; - spin_unlock(&smi_info->count_lock); + if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) { + smi_inc_stat(smi_info, complete_transactions); handle_transaction_done(smi_info); si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - } - else if (si_sm_result == SI_SM_HOSED) - { - spin_lock(&smi_info->count_lock); - smi_info->hosed_count++; - spin_unlock(&smi_info->count_lock); + } else if (si_sm_result == SI_SM_HOSED) { + smi_inc_stat(smi_info, hosed_count); - /* Do the before return_hosed_msg, because that - releases the lock. */ + /* + * Do the before return_hosed_msg, because that + * releases the lock. + */ smi_info->si_state = SI_NORMAL; if (smi_info->curr_msg != NULL) { - /* If we were handling a user message, format - a response to send to the upper layer to - tell it about the error. */ + /* + * If we were handling a user message, format + * a response to send to the upper layer to + * tell it about the error. + */ return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); } - /* We prefer handling attn over new messages. */ - if (si_sm_result == SI_SM_ATTN) - { + /* + * We prefer handling attn over new messages. But don't do + * this if there is not yet an upper layer to handle anything. + */ + if (likely(smi_info->intf) && si_sm_result == SI_SM_ATTN) { unsigned char msg[2]; - spin_lock(&smi_info->count_lock); - smi_info->attentions++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, attentions); - /* Got a attn, send down a get message flags to see - what's causing it. It would be better to handle - this in the upper layer, but due to the way - interrupts work with the SMI, that's not really - possible. */ + /* + * Got a attn, send down a get message flags to see + * what's causing it. It would be better to handle + * this in the upper layer, but due to the way + * interrupts work with the SMI, that's not really + * possible. + */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_MSG_FLAGS_CMD; @@ -748,20 +815,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, /* If we are currently idle, try to start the next message. */ if (si_sm_result == SI_SM_IDLE) { - spin_lock(&smi_info->count_lock); - smi_info->idles++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, idles); si_sm_result = start_next_msg(smi_info); if (si_sm_result != SI_SM_IDLE) goto restart; - } + } if ((si_sm_result == SI_SM_IDLE) - && (atomic_read(&smi_info->req_events))) - { - /* We are idle and the upper layer requested that I fetch - events, so do so. */ + && (atomic_read(&smi_info->req_events))) { + /* + * We are idle and the upper layer requested that I fetch + * events, so do so. + */ atomic_set(&smi_info->req_events, 0); smi_info->curr_msg = ipmi_alloc_smi_msg(); @@ -803,56 +869,50 @@ static void sender(void *send_info, return; } - spin_lock_irqsave(&(smi_info->msg_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif if (smi_info->run_to_completion) { - /* If we are running to completion, then throw it in - the list and run transactions until everything is - clear. Priority doesn't matter here. */ + /* + * If we are running to completion, then throw it in + * the list and run transactions until everything is + * clear. Priority doesn't matter here. + */ + + /* + * Run to completion means we are single-threaded, no + * need for locks. + */ list_add_tail(&(msg->link), &(smi_info->xmit_msgs)); - /* We have to release the msg lock and claim the smi - lock in this case, because of race conditions. */ - spin_unlock_irqrestore(&(smi_info->msg_lock), flags); - - spin_lock_irqsave(&(smi_info->si_lock), flags); result = smi_event_handler(smi_info, 0); while (result != SI_SM_IDLE) { udelay(SI_SHORT_TIMEOUT_USEC); result = smi_event_handler(smi_info, SI_SHORT_TIMEOUT_USEC); } - spin_unlock_irqrestore(&(smi_info->si_lock), flags); return; - } else { - if (priority > 0) { - list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs)); - } else { - list_add_tail(&(msg->link), &(smi_info->xmit_msgs)); - } } - spin_unlock_irqrestore(&(smi_info->msg_lock), flags); - spin_lock_irqsave(&(smi_info->si_lock), flags); - if ((smi_info->si_state == SI_NORMAL) - && (smi_info->curr_msg == NULL)) - { + spin_lock_irqsave(&smi_info->msg_lock, flags); + if (priority > 0) + list_add_tail(&msg->link, &smi_info->hp_xmit_msgs); + else + list_add_tail(&msg->link, &smi_info->xmit_msgs); + spin_unlock_irqrestore(&smi_info->msg_lock, flags); + + spin_lock_irqsave(&smi_info->si_lock, flags); + if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) start_next_msg(smi_info); - } - spin_unlock_irqrestore(&(smi_info->si_lock), flags); + spin_unlock_irqrestore(&smi_info->si_lock, flags); } static void set_run_to_completion(void *send_info, int i_run_to_completion) { struct smi_info *smi_info = send_info; enum si_sm_result result; - unsigned long flags; - - spin_lock_irqsave(&(smi_info->si_lock), flags); smi_info->run_to_completion = i_run_to_completion; if (i_run_to_completion) { @@ -863,8 +923,6 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) SI_SHORT_TIMEOUT_USEC); } } - - spin_unlock_irqrestore(&(smi_info->si_lock), flags); } static int ipmi_thread(void *data) @@ -878,9 +936,8 @@ static int ipmi_thread(void *data) spin_lock_irqsave(&(smi_info->si_lock), flags); smi_result = smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); - if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { - /* do nothing */ - } + if (smi_result == SI_SM_CALL_WITHOUT_DELAY) + ; /* do nothing */ else if (smi_result == SI_SM_CALL_WITH_DELAY) schedule(); else @@ -931,7 +988,7 @@ static void smi_timeout(unsigned long data) spin_lock_irqsave(&(smi_info->si_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif jiffies_now = jiffies; time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies) @@ -945,23 +1002,19 @@ static void smi_timeout(unsigned long data) if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { /* Running with interrupts, only do long timeouts. */ smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->long_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, long_timeouts); goto do_add_timer; } - /* If the state machine asks for a short delay, then shorten - the timer timeout. */ + /* + * If the state machine asks for a short delay, then shorten + * the timer timeout. + */ if (smi_result == SI_SM_CALL_WITH_DELAY) { - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->short_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, short_timeouts); smi_info->si_timer.expires = jiffies + 1; } else { - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->long_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, long_timeouts); smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; } @@ -979,13 +1032,11 @@ static irqreturn_t si_irq_handler(int irq, void *data) spin_lock_irqsave(&(smi_info->si_lock), flags); - spin_lock(&smi_info->count_lock); - smi_info->interrupts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, interrupts); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); @@ -1028,7 +1079,7 @@ static int smi_start_processing(void *send_info, * The BT interface is efficient enough to not need a thread, * and there is no need for a thread if we have interrupts. */ - else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) + else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) enable = 1; if (enable) { @@ -1054,8 +1105,7 @@ static void set_maintenance_mode(void *send_info, int enable) atomic_set(&smi_info->req_events, 0); } -static struct ipmi_smi_handlers handlers = -{ +static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .sender = sender, @@ -1065,8 +1115,10 @@ static struct ipmi_smi_handlers handlers = .poll = poll, }; -/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses, - a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */ +/* + * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, + * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. + */ static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); @@ -1257,10 +1309,9 @@ static void port_cleanup(struct smi_info *info) int idx; if (addr) { - for (idx = 0; idx < info->io_size; idx++) { + for (idx = 0; idx < info->io_size; idx++) release_region(addr + idx * info->io.regspacing, info->io.regsize); - } } } @@ -1274,8 +1325,10 @@ static int port_setup(struct smi_info *info) info->io_cleanup = port_cleanup; - /* Figure out the actual inb/inw/inl/etc routine to use based - upon the register size. */ + /* + * Figure out the actual inb/inw/inl/etc routine to use based + * upon the register size. + */ switch (info->io.regsize) { case 1: info->io.inputb = port_inb; @@ -1290,17 +1343,18 @@ static int port_setup(struct smi_info *info) info->io.outputb = port_outl; break; default: - printk("ipmi_si: Invalid register size: %d\n", + printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", info->io.regsize); return -EINVAL; } - /* Some BIOSes reserve disjoint I/O regions in their ACPI + /* + * Some BIOSes reserve disjoint I/O regions in their ACPI * tables. This causes problems when trying to register the * entire I/O region. Therefore we must register each I/O * port separately. */ - for (idx = 0; idx < info->io_size; idx++) { + for (idx = 0; idx < info->io_size; idx++) { if (request_region(addr + idx * info->io.regspacing, info->io.regsize, DEVICE_NAME) == NULL) { /* Undo allocations */ @@ -1388,8 +1442,10 @@ static int mem_setup(struct smi_info *info) info->io_cleanup = mem_cleanup; - /* Figure out the actual readb/readw/readl/etc routine to use based - upon the register size. */ + /* + * Figure out the actual readb/readw/readl/etc routine to use based + * upon the register size. + */ switch (info->io.regsize) { case 1: info->io.inputb = intf_mem_inb; @@ -1410,16 +1466,18 @@ static int mem_setup(struct smi_info *info) break; #endif default: - printk("ipmi_si: Invalid register size: %d\n", + printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", info->io.regsize); return -EINVAL; } - /* Calculate the total amount of memory to claim. This is an + /* + * Calculate the total amount of memory to claim. This is an * unusual looking calculation, but it avoids claiming any * more memory than it has to. It will claim everything * between the first address to the end of the last full - * register. */ + * register. + */ mapsize = ((info->io_size * info->io.regspacing) - (info->io.regspacing - info->io.regsize)); @@ -1749,9 +1807,11 @@ static __devinit void hardcode_find_bmc(void) #include <linux/acpi.h> -/* Once we get an ACPI failure, we don't try any more, because we go - through the tables sequentially. Once we don't find a table, there - are no more. */ +/* + * Once we get an ACPI failure, we don't try any more, because we go + * through the tables sequentially. Once we don't find a table, there + * are no more. + */ static int acpi_failure; /* For GPE-type interrupts. */ @@ -1765,9 +1825,7 @@ static u32 ipmi_acpi_gpe(void *context) spin_lock_irqsave(&(smi_info->si_lock), flags); - spin_lock(&smi_info->count_lock); - smi_info->interrupts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, interrupts); #ifdef DEBUG_TIMING do_gettimeofday(&t); @@ -1816,7 +1874,8 @@ static int acpi_gpe_irq_setup(struct smi_info *info) /* * Defined at - * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf + * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/ + * Docs/TechPapers/IA64/hpspmi.pdf */ struct SPMITable { s8 Signature[4]; @@ -1838,14 +1897,18 @@ struct SPMITable { */ u8 InterruptType; - /* If bit 0 of InterruptType is set, then this is the SCI - interrupt in the GPEx_STS register. */ + /* + * If bit 0 of InterruptType is set, then this is the SCI + * interrupt in the GPEx_STS register. + */ u8 GPE; s16 Reserved; - /* If bit 1 of InterruptType is set, then this is the I/O - APIC/SAPIC interrupt. */ + /* + * If bit 1 of InterruptType is set, then this is the I/O + * APIC/SAPIC interrupt. + */ u32 GlobalSystemInterrupt; /* The actual register address. */ @@ -1863,7 +1926,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) if (spmi->IPMIlegacy != 1) { printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy); - return -ENODEV; + return -ENODEV; } if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) @@ -1880,8 +1943,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->addr_source = "ACPI"; /* Figure out the interface type. */ - switch (spmi->InterfaceType) - { + switch (spmi->InterfaceType) { case 1: /* KCS */ info->si_type = SI_KCS; break; @@ -1929,7 +1991,8 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); - printk("ipmi_si: Unknown ACPI I/O Address type\n"); + printk(KERN_WARNING + "ipmi_si: Unknown ACPI I/O Address type\n"); return -EIO; } info->io.addr_data = spmi->addr.address; @@ -1963,8 +2026,7 @@ static __devinit void acpi_find_bmc(void) #endif #ifdef CONFIG_DMI -struct dmi_ipmi_data -{ +struct dmi_ipmi_data { u8 type; u8 addr_space; unsigned long base_addr; @@ -1989,11 +2051,10 @@ static int __devinit decode_dmi(const struct dmi_header *dm, /* I/O */ base_addr &= 0xFFFE; dmi->addr_space = IPMI_IO_ADDR_SPACE; - } - else { + } else /* Memory */ dmi->addr_space = IPMI_MEM_ADDR_SPACE; - } + /* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); @@ -2002,7 +2063,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, /* The top two bits of byte 0x10 hold the register spacing. */ reg_spacing = (data[0x10] & 0xC0) >> 6; - switch(reg_spacing){ + switch (reg_spacing) { case 0x00: /* Byte boundaries */ dmi->offset = 1; break; @@ -2018,12 +2079,14 @@ static int __devinit decode_dmi(const struct dmi_header *dm, } } else { /* Old DMI spec. */ - /* Note that technically, the lower bit of the base + /* + * Note that technically, the lower bit of the base * address should be 1 if the address is I/O and 0 if * the address is in memory. So many systems get that * wrong (and all that I have seen are I/O) so we just * ignore that bit and assume I/O. Systems that use - * memory should use the newer spec, anyway. */ + * memory should use the newer spec, anyway. + */ dmi->base_addr = base_addr & 0xfffe; dmi->addr_space = IPMI_IO_ADDR_SPACE; dmi->offset = 1; @@ -2230,13 +2293,13 @@ static struct pci_device_id ipmi_pci_devices[] = { MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); static struct pci_driver ipmi_pci_driver = { - .name = DEVICE_NAME, - .id_table = ipmi_pci_devices, - .probe = ipmi_pci_probe, - .remove = __devexit_p(ipmi_pci_remove), + .name = DEVICE_NAME, + .id_table = ipmi_pci_devices, + .probe = ipmi_pci_probe, + .remove = __devexit_p(ipmi_pci_remove), #ifdef CONFIG_PM - .suspend = ipmi_pci_suspend, - .resume = ipmi_pci_resume, + .suspend = ipmi_pci_suspend, + .resume = ipmi_pci_resume, #endif }; #endif /* CONFIG_PCI */ @@ -2306,7 +2369,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev, info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - dev->dev.driver_data = (void*) info; + dev->dev.driver_data = (void *) info; return try_smi_init(info); } @@ -2319,14 +2382,16 @@ static int __devexit ipmi_of_remove(struct of_device *dev) static struct of_device_id ipmi_match[] = { - { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS }, - { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC }, - { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT }, + { .type = "ipmi", .compatible = "ipmi-kcs", + .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", + .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", + .data = (void *)(unsigned long) SI_BT }, {}, }; -static struct of_platform_driver ipmi_of_platform_driver = -{ +static struct of_platform_driver ipmi_of_platform_driver = { .name = "ipmi", .match_table = ipmi_match, .probe = ipmi_of_probe, @@ -2347,32 +2412,32 @@ static int try_get_dev_id(struct smi_info *smi_info) if (!resp) return -ENOMEM; - /* Do a Get Device ID command, since it comes back with some - useful info. */ + /* + * Do a Get Device ID command, since it comes back with some + * useful info. + */ msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_GET_DEVICE_ID_CMD; smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); smi_result = smi_info->handlers->event(smi_info->si_sm, 0); - for (;;) - { + for (;;) { if (smi_result == SI_SM_CALL_WITH_DELAY || smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( smi_info->si_sm, 100); - } - else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) - { + } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { smi_result = smi_info->handlers->event( smi_info->si_sm, 0); - } - else + } else break; } if (smi_result == SI_SM_HOSED) { - /* We couldn't get the state machine to run, so whatever's at - the port is probably not an IPMI SMI interface. */ + /* + * We couldn't get the state machine to run, so whatever's at + * the port is probably not an IPMI SMI interface. + */ rv = -ENODEV; goto out; } @@ -2405,30 +2470,28 @@ static int stat_file_read_proc(char *page, char **start, off_t off, out += sprintf(out, "interrupts_enabled: %d\n", smi->irq && !smi->interrupt_disabled); - out += sprintf(out, "short_timeouts: %ld\n", - smi->short_timeouts); - out += sprintf(out, "long_timeouts: %ld\n", - smi->long_timeouts); - out += sprintf(out, "timeout_restarts: %ld\n", - smi->timeout_restarts); - out += sprintf(out, "idles: %ld\n", - smi->idles); - out += sprintf(out, "interrupts: %ld\n", - smi->interrupts); - out += sprintf(out, "attentions: %ld\n", - smi->attentions); - out += sprintf(out, "flag_fetches: %ld\n", - smi->flag_fetches); - out += sprintf(out, "hosed_count: %ld\n", - smi->hosed_count); - out += sprintf(out, "complete_transactions: %ld\n", - smi->complete_transactions); - out += sprintf(out, "events: %ld\n", - smi->events); - out += sprintf(out, "watchdog_pretimeouts: %ld\n", - smi->watchdog_pretimeouts); - out += sprintf(out, "incoming_messages: %ld\n", - smi->incoming_messages); + out += sprintf(out, "short_timeouts: %u\n", + smi_get_stat(smi, short_timeouts)); + out += sprintf(out, "long_timeouts: %u\n", + smi_get_stat(smi, long_timeouts)); + out += sprintf(out, "idles: %u\n", + smi_get_stat(smi, idles)); + out += sprintf(out, "interrupts: %u\n", + smi_get_stat(smi, interrupts)); + out += sprintf(out, "attentions: %u\n", + smi_get_stat(smi, attentions)); + out += sprintf(out, "flag_fetches: %u\n", + smi_get_stat(smi, flag_fetches)); + out += sprintf(out, "hosed_count: %u\n", + smi_get_stat(smi, hosed_count)); + out += sprintf(out, "complete_transactions: %u\n", + smi_get_stat(smi, complete_transactions)); + out += sprintf(out, "events: %u\n", + smi_get_stat(smi, events)); + out += sprintf(out, "watchdog_pretimeouts: %u\n", + smi_get_stat(smi, watchdog_pretimeouts)); + out += sprintf(out, "incoming_messages: %u\n", + smi_get_stat(smi, incoming_messages)); return out - page; } @@ -2460,7 +2523,7 @@ static int param_read_proc(char *page, char **start, off_t off, static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) { smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) | - RECEIVE_MSG_AVAIL); + RECEIVE_MSG_AVAIL); return 1; } @@ -2502,10 +2565,9 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; - } - else if (ipmi_version_major(id) < 1 || - (ipmi_version_major(id) == 1 && - ipmi_version_minor(id) < 5)) { + } else if (ipmi_version_major(id) < 1 || + (ipmi_version_major(id) == 1 && + ipmi_version_minor(id) < 5)) { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; } @@ -2597,8 +2659,10 @@ static void setup_xaction_handlers(struct smi_info *smi_info) static inline void wait_for_timer_and_thread(struct smi_info *smi_info) { if (smi_info->intf) { - /* The timer and thread are only running if the - interface has been started up and registered. */ + /* + * The timer and thread are only running if the + * interface has been started up and registered. + */ if (smi_info->thread != NULL) kthread_stop(smi_info->thread); del_timer_sync(&smi_info->si_timer); @@ -2676,6 +2740,7 @@ static int is_new_interface(struct smi_info *info) static int try_smi_init(struct smi_info *new_smi) { int rv; + int i; if (new_smi->addr_source) { printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" @@ -2722,7 +2787,7 @@ static int try_smi_init(struct smi_info *new_smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { - printk(" Could not allocate state machine memory\n"); + printk(KERN_ERR "Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; } @@ -2732,13 +2797,12 @@ static int try_smi_init(struct smi_info *new_smi) /* Now that we know the I/O size, we can set up the I/O. */ rv = new_smi->io_setup(new_smi); if (rv) { - printk(" Could not set up I/O space\n"); + printk(KERN_ERR "Could not set up I/O space\n"); goto out_err; } spin_lock_init(&(new_smi->si_lock)); spin_lock_init(&(new_smi->msg_lock)); - spin_lock_init(&(new_smi->count_lock)); /* Do low-level detection first. */ if (new_smi->handlers->detect(new_smi->si_sm)) { @@ -2749,8 +2813,10 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } - /* Attempt a get device id command. If it fails, we probably - don't have a BMC here. */ + /* + * Attempt a get device id command. If it fails, we probably + * don't have a BMC here. + */ rv = try_get_dev_id(new_smi); if (rv) { if (new_smi->addr_source) @@ -2767,22 +2833,28 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->curr_msg = NULL; atomic_set(&new_smi->req_events, 0); new_smi->run_to_completion = 0; + for (i = 0; i < SI_NUM_STATS; i++) + atomic_set(&new_smi->stats[i], 0); new_smi->interrupt_disabled = 0; atomic_set(&new_smi->stop_operation, 0); new_smi->intf_num = smi_num; smi_num++; - /* Start clearing the flags before we enable interrupts or the - timer to avoid racing with the timer. */ + /* + * Start clearing the flags before we enable interrupts or the + * timer to avoid racing with the timer. + */ start_clear_flags(new_smi); /* IRQ is defined to be set when non-zero. */ if (new_smi->irq) new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; if (!new_smi->dev) { - /* If we don't already have a device from something - * else (like PCI), then register a new one. */ + /* + * If we don't already have a device from something + * else (like PCI), then register a new one. + */ new_smi->pdev = platform_device_alloc("ipmi_si", new_smi->intf_num); if (rv) { @@ -2820,7 +2892,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", - type_file_read_proc, NULL, + type_file_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2830,7 +2902,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats", - stat_file_read_proc, NULL, + stat_file_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2840,7 +2912,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", - param_read_proc, NULL, + param_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2853,7 +2925,8 @@ static int try_smi_init(struct smi_info *new_smi) mutex_unlock(&smi_infos_lock); - printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); + printk(KERN_INFO "IPMI %s interface initialized\n", + si_to_str[new_smi->si_type]); return 0; @@ -2868,9 +2941,11 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->irq_cleanup) new_smi->irq_cleanup(new_smi); - /* Wait until we know that we are out of any interrupt - handlers might have been running before we freed the - interrupt. */ + /* + * Wait until we know that we are out of any interrupt + * handlers might have been running before we freed the + * interrupt. + */ synchronize_sched(); if (new_smi->si_sm) { @@ -2942,11 +3017,10 @@ static __devinit int init_ipmi_si(void) #ifdef CONFIG_PCI rv = pci_register_driver(&ipmi_pci_driver); - if (rv){ + if (rv) printk(KERN_ERR "init_ipmi_si: Unable to register PCI driver: %d\n", rv); - } #endif #ifdef CONFIG_PPC_OF @@ -2975,7 +3049,8 @@ static __devinit int init_ipmi_si(void) of_unregister_platform_driver(&ipmi_of_platform_driver); #endif driver_unregister(&ipmi_driver); - printk("ipmi_si: Unable to find any System Interface(s)\n"); + printk(KERN_WARNING + "ipmi_si: Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); @@ -2997,13 +3072,17 @@ static void cleanup_one_si(struct smi_info *to_clean) /* Tell the driver that we are shutting down. */ atomic_inc(&to_clean->stop_operation); - /* Make sure the timer and thread are stopped and will not run - again. */ + /* + * Make sure the timer and thread are stopped and will not run + * again. + */ wait_for_timer_and_thread(to_clean); - /* Timeouts are stopped, now make sure the interrupts are off - for the device. A little tricky with locks to make sure - there are no races. */ + /* + * Timeouts are stopped, now make sure the interrupts are off + * for the device. A little tricky with locks to make sure + * there are no races. + */ spin_lock_irqsave(&to_clean->si_lock, flags); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { spin_unlock_irqrestore(&to_clean->si_lock, flags); @@ -3074,4 +3153,5 @@ module_exit(cleanup_ipmi_si); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); -MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces."); +MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT" + " system interfaces."); diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index 4b731b24dc16..df89f73475fb 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -34,22 +34,27 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* This is defined by the state machines themselves, it is an opaque - data type for them to use. */ +/* + * This is defined by the state machines themselves, it is an opaque + * data type for them to use. + */ struct si_sm_data; -/* The structure for doing I/O in the state machine. The state - machine doesn't have the actual I/O routines, they are done through - this interface. */ -struct si_sm_io -{ +/* + * The structure for doing I/O in the state machine. The state + * machine doesn't have the actual I/O routines, they are done through + * this interface. + */ +struct si_sm_io { unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset); void (*outputb)(struct si_sm_io *io, unsigned int offset, unsigned char b); - /* Generic info used by the actual handling routines, the - state machine shouldn't touch these. */ + /* + * Generic info used by the actual handling routines, the + * state machine shouldn't touch these. + */ void __iomem *addr; int regspacing; int regsize; @@ -59,53 +64,67 @@ struct si_sm_io }; /* Results of SMI events. */ -enum si_sm_result -{ +enum si_sm_result { SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */ SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */ - SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */ + SI_SM_CALL_WITH_TICK_DELAY,/* Delay >=1 tick before calling again. */ SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */ SI_SM_IDLE, /* The SM is in idle state. */ SI_SM_HOSED, /* The hardware violated the state machine. */ - SI_SM_ATTN /* The hardware is asserting attn and the - state machine is idle. */ + + /* + * The hardware is asserting attn and the state machine is + * idle. + */ + SI_SM_ATTN }; /* Handlers for the SMI state machine. */ -struct si_sm_handlers -{ - /* Put the version number of the state machine here so the - upper layer can print it. */ +struct si_sm_handlers { + /* + * Put the version number of the state machine here so the + * upper layer can print it. + */ char *version; - /* Initialize the data and return the amount of I/O space to - reserve for the space. */ + /* + * Initialize the data and return the amount of I/O space to + * reserve for the space. + */ unsigned int (*init_data)(struct si_sm_data *smi, struct si_sm_io *io); - /* Start a new transaction in the state machine. This will - return -2 if the state machine is not idle, -1 if the size - is invalid (to large or too small), or 0 if the transaction - is successfully completed. */ + /* + * Start a new transaction in the state machine. This will + * return -2 if the state machine is not idle, -1 if the size + * is invalid (to large or too small), or 0 if the transaction + * is successfully completed. + */ int (*start_transaction)(struct si_sm_data *smi, unsigned char *data, unsigned int size); - /* Return the results after the transaction. This will return - -1 if the buffer is too small, zero if no transaction is - present, or the actual length of the result data. */ + /* + * Return the results after the transaction. This will return + * -1 if the buffer is too small, zero if no transaction is + * present, or the actual length of the result data. + */ int (*get_result)(struct si_sm_data *smi, unsigned char *data, unsigned int length); - /* Call this periodically (for a polled interface) or upon - receiving an interrupt (for a interrupt-driven interface). - If interrupt driven, you should probably poll this - periodically when not in idle state. This should be called - with the time that passed since the last call, if it is - significant. Time is in microseconds. */ + /* + * Call this periodically (for a polled interface) or upon + * receiving an interrupt (for a interrupt-driven interface). + * If interrupt driven, you should probably poll this + * periodically when not in idle state. This should be called + * with the time that passed since the last call, if it is + * significant. Time is in microseconds. + */ enum si_sm_result (*event)(struct si_sm_data *smi, long time); - /* Attempt to detect an SMI. Returns 0 on success or nonzero - on failure. */ + /* + * Attempt to detect an SMI. Returns 0 on success or nonzero + * on failure. + */ int (*detect)(struct si_sm_data *smi); /* The interface is shutting down, so clean it up. */ diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index e64ea7d25d24..faed92971907 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -85,6 +85,7 @@ enum smic_states { /* SMIC Flags Register Bits */ #define SMIC_RX_DATA_READY 0x80 #define SMIC_TX_DATA_READY 0x40 + /* * SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by * a few systems, and then only by Systems Management @@ -104,23 +105,22 @@ enum smic_states { #define EC_ILLEGAL_COMMAND 0x04 #define EC_BUFFER_FULL 0x05 -struct si_sm_data -{ +struct si_sm_data { enum smic_states state; struct si_sm_io *io; - unsigned char write_data[MAX_SMIC_WRITE_SIZE]; - int write_pos; - int write_count; - int orig_write_count; - unsigned char read_data[MAX_SMIC_READ_SIZE]; - int read_pos; - int truncated; - unsigned int error_retries; - long smic_timeout; + unsigned char write_data[MAX_SMIC_WRITE_SIZE]; + int write_pos; + int write_count; + int orig_write_count; + unsigned char read_data[MAX_SMIC_READ_SIZE]; + int read_pos; + int truncated; + unsigned int error_retries; + long smic_timeout; }; -static unsigned int init_smic_data (struct si_sm_data *smic, - struct si_sm_io *io) +static unsigned int init_smic_data(struct si_sm_data *smic, + struct si_sm_io *io) { smic->state = SMIC_IDLE; smic->io = io; @@ -150,11 +150,10 @@ static int start_smic_transaction(struct si_sm_data *smic, return IPMI_NOT_IN_MY_STATE_ERR; if (smic_debug & SMIC_DEBUG_MSG) { - printk(KERN_INFO "start_smic_transaction -"); - for (i = 0; i < size; i ++) { - printk (" %02x", (unsigned char) (data [i])); - } - printk ("\n"); + printk(KERN_DEBUG "start_smic_transaction -"); + for (i = 0; i < size; i++) + printk(" %02x", (unsigned char) data[i]); + printk("\n"); } smic->error_retries = 0; memcpy(smic->write_data, data, size); @@ -173,11 +172,10 @@ static int smic_get_result(struct si_sm_data *smic, int i; if (smic_debug & SMIC_DEBUG_MSG) { - printk (KERN_INFO "smic_get result -"); - for (i = 0; i < smic->read_pos; i ++) { - printk (" %02x", (smic->read_data [i])); - } - printk ("\n"); + printk(KERN_DEBUG "smic_get result -"); + for (i = 0; i < smic->read_pos; i++) + printk(" %02x", smic->read_data[i]); + printk("\n"); } if (length < smic->read_pos) { smic->read_pos = length; @@ -223,8 +221,8 @@ static inline void write_smic_control(struct si_sm_data *smic, smic->io->outputb(smic->io, 1, control); } -static inline void write_si_sm_data (struct si_sm_data *smic, - unsigned char data) +static inline void write_si_sm_data(struct si_sm_data *smic, + unsigned char data) { smic->io->outputb(smic->io, 0, data); } @@ -233,10 +231,9 @@ static inline void start_error_recovery(struct si_sm_data *smic, char *reason) { (smic->error_retries)++; if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) { - if (smic_debug & SMIC_DEBUG_ENABLE) { + if (smic_debug & SMIC_DEBUG_ENABLE) printk(KERN_WARNING "ipmi_smic_drv: smic hosed: %s\n", reason); - } smic->state = SMIC_HOSED; } else { smic->write_count = smic->orig_write_count; @@ -254,14 +251,14 @@ static inline void write_next_byte(struct si_sm_data *smic) (smic->write_count)--; } -static inline void read_next_byte (struct si_sm_data *smic) +static inline void read_next_byte(struct si_sm_data *smic) { if (smic->read_pos >= MAX_SMIC_READ_SIZE) { - read_smic_data (smic); + read_smic_data(smic); smic->truncated = 1; } else { smic->read_data[smic->read_pos] = read_smic_data(smic); - (smic->read_pos)++; + smic->read_pos++; } } @@ -336,7 +333,7 @@ static inline void read_next_byte (struct si_sm_data *smic) SMIC_SC_SMS_RD_END 0xC6 */ -static enum si_sm_result smic_event (struct si_sm_data *smic, long time) +static enum si_sm_result smic_event(struct si_sm_data *smic, long time) { unsigned char status; unsigned char flags; @@ -347,13 +344,15 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) return SI_SM_HOSED; } if (smic->state != SMIC_IDLE) { - if (smic_debug & SMIC_DEBUG_STATES) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_STATES) + printk(KERN_DEBUG "smic_event - smic->smic_timeout = %ld," " time = %ld\n", smic->smic_timeout, time); - } -/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */ + /* + * FIXME: smic_event is sometimes called with time > + * SMIC_RETRY_TIMEOUT + */ if (time < SMIC_RETRY_TIMEOUT) { smic->smic_timeout -= time; if (smic->smic_timeout < 0) { @@ -366,9 +365,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) if (flags & SMIC_FLAG_BSY) return SI_SM_CALL_WITH_DELAY; - status = read_smic_status (smic); + status = read_smic_status(smic); if (smic_debug & SMIC_DEBUG_STATES) - printk(KERN_INFO + printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x," " status = 0x%02x\n", smic->state, flags, status); @@ -377,9 +376,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) case SMIC_IDLE: /* in IDLE we check for available messages */ if (flags & SMIC_SMS_DATA_AVAIL) - { return SI_SM_ATTN; - } return SI_SM_IDLE; case SMIC_START_OP: @@ -391,7 +388,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) case SMIC_OP_OK: if (status != SMIC_SC_SMS_READY) { - /* this should not happen */ + /* this should not happen */ start_error_recovery(smic, "state = SMIC_OP_OK," " status != SMIC_SC_SMS_READY"); @@ -411,8 +408,10 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) "status != SMIC_SC_SMS_WR_START"); return SI_SM_CALL_WITH_DELAY; } - /* we must not issue WR_(NEXT|END) unless - TX_DATA_READY is set */ + /* + * we must not issue WR_(NEXT|END) unless + * TX_DATA_READY is set + * */ if (flags & SMIC_TX_DATA_READY) { if (smic->write_count == 1) { /* last byte */ @@ -424,10 +423,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) } write_next_byte(smic); write_smic_flags(smic, flags | SMIC_FLAG_BSY); - } - else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_WRITE_NEXT: @@ -442,52 +439,48 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) if (smic->write_count == 1) { write_smic_control(smic, SMIC_CC_SMS_WR_END); smic->state = SMIC_WRITE_END; - } - else { + } else { write_smic_control(smic, SMIC_CC_SMS_WR_NEXT); smic->state = SMIC_WRITE_NEXT; } write_next_byte(smic); write_smic_flags(smic, flags | SMIC_FLAG_BSY); - } - else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_WRITE_END: if (status != SMIC_SC_SMS_WR_END) { - start_error_recovery (smic, - "state = SMIC_WRITE_END, " - "status != SMIC_SC_SMS_WR_END"); + start_error_recovery(smic, + "state = SMIC_WRITE_END, " + "status != SMIC_SC_SMS_WR_END"); return SI_SM_CALL_WITH_DELAY; } /* data register holds an error code */ data = read_smic_data(smic); if (data != 0) { - if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_ENABLE) + printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n", data); - } start_error_recovery(smic, "state = SMIC_WRITE_END, " "data != SUCCESS"); return SI_SM_CALL_WITH_DELAY; - } else { + } else smic->state = SMIC_WRITE2READ; - } break; case SMIC_WRITE2READ: - /* we must wait for RX_DATA_READY to be set before we - can continue */ + /* + * we must wait for RX_DATA_READY to be set before we + * can continue + */ if (flags & SMIC_RX_DATA_READY) { write_smic_control(smic, SMIC_CC_SMS_RD_START); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_START; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_READ_START: @@ -502,15 +495,16 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_NEXT; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_READ_NEXT: switch (status) { - /* smic tells us that this is the last byte to be read - --> clean up */ + /* + * smic tells us that this is the last byte to be read + * --> clean up + */ case SMIC_SC_SMS_RD_END: read_next_byte(smic); write_smic_control(smic, SMIC_CC_SMS_RD_END); @@ -523,9 +517,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_NEXT; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; default: start_error_recovery( @@ -546,10 +539,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) data = read_smic_data(smic); /* data register holds an error code */ if (data != 0) { - if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_ENABLE) + printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n", data); - } start_error_recovery(smic, "state = SMIC_READ_END, " "data != SUCCESS"); @@ -565,7 +557,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) default: if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_WARNING "smic->state = %d\n", smic->state); + printk(KERN_DEBUG "smic->state = %d\n", smic->state); start_error_recovery(smic, "state = UNKNOWN"); return SI_SM_CALL_WITH_DELAY; } @@ -576,10 +568,12 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) static int smic_detect(struct si_sm_data *smic) { - /* It's impossible for the SMIC fnags register to be all 1's, - (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. */ + /* + * It's impossible for the SMIC fnags register to be all 1's, + * (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. + */ if (read_smic_flags(smic) == 0xff) return 1; @@ -595,8 +589,7 @@ static int smic_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers smic_smi_handlers = -{ +struct si_sm_handlers smic_smi_handlers = { .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 8f45ca9235ad..1b9a87047817 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -54,13 +54,15 @@ #include <asm/atomic.h> #ifdef CONFIG_X86 -/* This is ugly, but I've determined that x86 is the only architecture - that can reasonably support the IPMI NMI watchdog timeout at this - time. If another architecture adds this capability somehow, it - will have to be a somewhat different mechanism and I have no idea - how it will work. So in the unlikely event that another - architecture supports this, we can figure out a good generic - mechanism for it at that time. */ +/* + * This is ugly, but I've determined that x86 is the only architecture + * that can reasonably support the IPMI NMI watchdog timeout at this + * time. If another architecture adds this capability somehow, it + * will have to be a somewhat different mechanism and I have no idea + * how it will work. So in the unlikely event that another + * architecture supports this, we can figure out a good generic + * mechanism for it at that time. + */ #include <asm/kdebug.h> #define HAVE_DIE_NMI #endif @@ -95,9 +97,8 @@ /* Operations that can be performed on a pretimout. */ #define WDOG_PREOP_NONE 0 #define WDOG_PREOP_PANIC 1 -#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to - read. Doesn't work in NMI - mode. */ +/* Cause data to be available to read. Doesn't work in NMI mode. */ +#define WDOG_PREOP_GIVE_DATA 2 /* Actions to perform on a full timeout. */ #define WDOG_SET_TIMEOUT_ACT(byte, use) \ @@ -108,8 +109,10 @@ #define WDOG_TIMEOUT_POWER_DOWN 2 #define WDOG_TIMEOUT_POWER_CYCLE 3 -/* Byte 3 of the get command, byte 4 of the get response is the - pre-timeout in seconds. */ +/* + * Byte 3 of the get command, byte 4 of the get response is the + * pre-timeout in seconds. + */ /* Bits for setting byte 4 of the set command, byte 5 of the get response. */ #define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1) @@ -118,11 +121,13 @@ #define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4) #define WDOG_EXPIRE_CLEAR_OEM (1 << 5) -/* Setting/getting the watchdog timer value. This is for bytes 5 and - 6 (the timeout time) of the set command, and bytes 6 and 7 (the - timeout time) and 8 and 9 (the current countdown value) of the - response. The timeout value is given in seconds (in the command it - is 100ms intervals). */ +/* + * Setting/getting the watchdog timer value. This is for bytes 5 and + * 6 (the timeout time) of the set command, and bytes 6 and 7 (the + * timeout time) and 8 and 9 (the current countdown value) of the + * response. The timeout value is given in seconds (in the command it + * is 100ms intervals). + */ #define WDOG_SET_TIMEOUT(byte1, byte2, val) \ (byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8) #define WDOG_GET_TIMEOUT(byte1, byte2) \ @@ -184,8 +189,10 @@ static int ipmi_set_timeout(int do_heartbeat); static void ipmi_register_watchdog(int ipmi_intf); static void ipmi_unregister_watchdog(int ipmi_intf); -/* If true, the driver will start running as soon as it is configured - and ready. */ +/* + * If true, the driver will start running as soon as it is configured + * and ready. + */ static int start_now; static int set_param_int(const char *val, struct kernel_param *kp) @@ -309,10 +316,12 @@ static int ipmi_ignore_heartbeat; /* Is someone using the watchdog? Only one user is allowed. */ static unsigned long ipmi_wdog_open; -/* If set to 1, the heartbeat command will set the state to reset and - start the timer. The timer doesn't normally run when the driver is - first opened until the heartbeat is set the first time, this - variable is used to accomplish this. */ +/* + * If set to 1, the heartbeat command will set the state to reset and + * start the timer. The timer doesn't normally run when the driver is + * first opened until the heartbeat is set the first time, this + * variable is used to accomplish this. + */ static int ipmi_start_timer_on_heartbeat; /* IPMI version of the BMC. */ @@ -329,10 +338,12 @@ static int nmi_handler_registered; static int ipmi_heartbeat(void); -/* We use a mutex to make sure that only one thing can send a set - timeout at one time, because we only have one copy of the data. - The mutex is claimed when the set_timeout is sent and freed - when both messages are free. */ +/* + * We use a mutex to make sure that only one thing can send a set + * timeout at one time, because we only have one copy of the data. + * The mutex is claimed when the set_timeout is sent and freed + * when both messages are free. + */ static atomic_t set_timeout_tofree = ATOMIC_INIT(0); static DEFINE_MUTEX(set_timeout_lock); static DECLARE_COMPLETION(set_timeout_wait); @@ -346,15 +357,13 @@ static void set_timeout_free_recv(struct ipmi_recv_msg *msg) if (atomic_dec_and_test(&set_timeout_tofree)) complete(&set_timeout_wait); } -static struct ipmi_smi_msg set_timeout_smi_msg = -{ +static struct ipmi_smi_msg set_timeout_smi_msg = { .done = set_timeout_free_smi }; -static struct ipmi_recv_msg set_timeout_recv_msg = -{ +static struct ipmi_recv_msg set_timeout_recv_msg = { .done = set_timeout_free_recv }; - + static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, int *send_heartbeat_now) @@ -373,13 +382,14 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); if ((ipmi_version_major > 1) - || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) - { + || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) { /* This is an IPMI 1.5-only feature. */ data[0] |= WDOG_DONT_STOP_ON_SET; } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { - /* In ipmi 1.0, setting the timer stops the watchdog, we - need to start it back up again. */ + /* + * In ipmi 1.0, setting the timer stops the watchdog, we + * need to start it back up again. + */ hbnow = 1; } @@ -465,12 +475,10 @@ static void panic_recv_free(struct ipmi_recv_msg *msg) atomic_dec(&panic_done_count); } -static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = -{ +static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = { .done = panic_smi_free }; -static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = -{ +static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = { .done = panic_recv_free }; @@ -480,8 +488,10 @@ static void panic_halt_ipmi_heartbeat(void) struct ipmi_system_interface_addr addr; int rv; - /* Don't reset the timer if we have the timer turned off, that - re-enables the watchdog. */ + /* + * Don't reset the timer if we have the timer turned off, that + * re-enables the watchdog. + */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) return; @@ -505,19 +515,19 @@ static void panic_halt_ipmi_heartbeat(void) atomic_add(2, &panic_done_count); } -static struct ipmi_smi_msg panic_halt_smi_msg = -{ +static struct ipmi_smi_msg panic_halt_smi_msg = { .done = panic_smi_free }; -static struct ipmi_recv_msg panic_halt_recv_msg = -{ +static struct ipmi_recv_msg panic_halt_recv_msg = { .done = panic_recv_free }; -/* Special call, doesn't claim any locks. This is only to be called - at panic or halt time, in run-to-completion mode, when the caller - is the only CPU and the only thing that will be going is these IPMI - calls. */ +/* + * Special call, doesn't claim any locks. This is only to be called + * at panic or halt time, in run-to-completion mode, when the caller + * is the only CPU and the only thing that will be going is these IPMI + * calls. + */ static void panic_halt_ipmi_set_timeout(void) { int send_heartbeat_now; @@ -540,10 +550,12 @@ static void panic_halt_ipmi_set_timeout(void) ipmi_poll_interface(watchdog_user); } -/* We use a semaphore to make sure that only one thing can send a - heartbeat at one time, because we only have one copy of the data. - The semaphore is claimed when the set_timeout is sent and freed - when both messages are free. */ +/* + * We use a mutex to make sure that only one thing can send a + * heartbeat at one time, because we only have one copy of the data. + * The semaphore is claimed when the set_timeout is sent and freed + * when both messages are free. + */ static atomic_t heartbeat_tofree = ATOMIC_INIT(0); static DEFINE_MUTEX(heartbeat_lock); static DECLARE_COMPLETION(heartbeat_wait); @@ -557,15 +569,13 @@ static void heartbeat_free_recv(struct ipmi_recv_msg *msg) if (atomic_dec_and_test(&heartbeat_tofree)) complete(&heartbeat_wait); } -static struct ipmi_smi_msg heartbeat_smi_msg = -{ +static struct ipmi_smi_msg heartbeat_smi_msg = { .done = heartbeat_free_smi }; -static struct ipmi_recv_msg heartbeat_recv_msg = -{ +static struct ipmi_recv_msg heartbeat_recv_msg = { .done = heartbeat_free_recv }; - + static int ipmi_heartbeat(void) { struct kernel_ipmi_msg msg; @@ -580,10 +590,12 @@ static int ipmi_heartbeat(void) ipmi_watchdog_state = action_val; return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } else if (pretimeout_since_last_heartbeat) { - /* A pretimeout occurred, make sure we set the timeout. - We don't want to set the action, though, we want to - leave that alone (thus it can't be combined with the - above operation. */ + /* + * A pretimeout occurred, make sure we set the timeout. + * We don't want to set the action, though, we want to + * leave that alone (thus it can't be combined with the + * above operation. + */ return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); } @@ -591,8 +603,10 @@ static int ipmi_heartbeat(void) atomic_set(&heartbeat_tofree, 2); - /* Don't reset the timer if we have the timer turned off, that - re-enables the watchdog. */ + /* + * Don't reset the timer if we have the timer turned off, that + * re-enables the watchdog. + */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) { mutex_unlock(&heartbeat_lock); return 0; @@ -625,10 +639,12 @@ static int ipmi_heartbeat(void) wait_for_completion(&heartbeat_wait); if (heartbeat_recv_msg.msg.data[0] != 0) { - /* Got an error in the heartbeat response. It was already - reported in ipmi_wdog_msg_handler, but we should return - an error here. */ - rv = -EINVAL; + /* + * Got an error in the heartbeat response. It was already + * reported in ipmi_wdog_msg_handler, but we should return + * an error here. + */ + rv = -EINVAL; } mutex_unlock(&heartbeat_lock); @@ -636,8 +652,7 @@ static int ipmi_heartbeat(void) return rv; } -static struct watchdog_info ident = -{ +static struct watchdog_info ident = { .options = 0, /* WDIOF_SETTIMEOUT, */ .firmware_version = 1, .identity = "IPMI" @@ -650,7 +665,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, int i; int val; - switch(cmd) { + switch (cmd) { case WDIOC_GETSUPPORT: i = copy_to_user(argp, &ident, sizeof(ident)); return i ? -EFAULT : 0; @@ -690,15 +705,13 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, i = copy_from_user(&val, argp, sizeof(int)); if (i) return -EFAULT; - if (val & WDIOS_DISABLECARD) - { + if (val & WDIOS_DISABLECARD) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); ipmi_start_timer_on_heartbeat = 0; } - if (val & WDIOS_ENABLECARD) - { + if (val & WDIOS_ENABLECARD) { ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } @@ -724,13 +737,13 @@ static ssize_t ipmi_write(struct file *file, int rv; if (len) { - if (!nowayout) { - size_t i; + if (!nowayout) { + size_t i; /* In case it was set long ago */ expect_close = 0; - for (i = 0; i != len; i++) { + for (i = 0; i != len; i++) { char c; if (get_user(c, buf + i)) @@ -758,15 +771,17 @@ static ssize_t ipmi_read(struct file *file, if (count <= 0) return 0; - /* Reading returns if the pretimeout has gone off, and it only does - it once per pretimeout. */ + /* + * Reading returns if the pretimeout has gone off, and it only does + * it once per pretimeout. + */ spin_lock(&ipmi_read_lock); if (!data_to_read) { if (file->f_flags & O_NONBLOCK) { rv = -EAGAIN; goto out; } - + init_waitqueue_entry(&wait, current); add_wait_queue(&read_q, &wait); while (!data_to_read) { @@ -776,7 +791,7 @@ static ssize_t ipmi_read(struct file *file, spin_lock(&ipmi_read_lock); } remove_wait_queue(&read_q, &wait); - + if (signal_pending(current)) { rv = -ERESTARTSYS; goto out; @@ -799,25 +814,27 @@ static ssize_t ipmi_read(struct file *file, static int ipmi_open(struct inode *ino, struct file *filep) { - switch (iminor(ino)) { - case WATCHDOG_MINOR: + switch (iminor(ino)) { + case WATCHDOG_MINOR: if (test_and_set_bit(0, &ipmi_wdog_open)) - return -EBUSY; + return -EBUSY; - /* Don't start the timer now, let it start on the - first heartbeat. */ + /* + * Don't start the timer now, let it start on the + * first heartbeat. + */ ipmi_start_timer_on_heartbeat = 1; return nonseekable_open(ino, filep); default: return (-ENODEV); - } + } } static unsigned int ipmi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - + poll_wait(file, &read_q, wait); spin_lock(&ipmi_read_lock); @@ -851,7 +868,7 @@ static int ipmi_close(struct inode *ino, struct file *filep) clear_bit(0, &ipmi_wdog_open); } - ipmi_fasync (-1, filep, 0); + ipmi_fasync(-1, filep, 0); expect_close = 0; return 0; @@ -882,7 +899,7 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, msg->msg.data[0], msg->msg.cmd); } - + ipmi_free_recv_msg(msg); } @@ -902,14 +919,14 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data) } } - /* On some machines, the heartbeat will give - an error and not work unless we re-enable - the timer. So do so. */ + /* + * On some machines, the heartbeat will give an error and not + * work unless we re-enable the timer. So do so. + */ pretimeout_since_last_heartbeat = 1; } -static struct ipmi_user_hndl ipmi_hndlrs = -{ +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_wdog_msg_handler, .ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler }; @@ -949,8 +966,10 @@ static void ipmi_register_watchdog(int ipmi_intf) int old_timeout = timeout; int old_preop_val = preop_val; - /* Set the pretimeout to go off in a second and give - ourselves plenty of time to stop the timer. */ + /* + * Set the pretimeout to go off in a second and give + * ourselves plenty of time to stop the timer. + */ ipmi_watchdog_state = WDOG_TIMEOUT_RESET; preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ pretimeout = 99; @@ -974,7 +993,7 @@ static void ipmi_register_watchdog(int ipmi_intf) " occur. The NMI pretimeout will" " likely not work\n"); } - out_restore: + out_restore: testing_nmi = 0; preop_val = old_preop_val; pretimeout = old_pretimeout; @@ -1009,9 +1028,11 @@ static void ipmi_unregister_watchdog(int ipmi_intf) /* Make sure no one can call us any more. */ misc_deregister(&ipmi_wdog_miscdev); - /* Wait to make sure the message makes it out. The lower layer has - pointers to our buffers, we want to make sure they are done before - we release our memory. */ + /* + * Wait to make sure the message makes it out. The lower layer has + * pointers to our buffers, we want to make sure they are done before + * we release our memory. + */ while (atomic_read(&set_timeout_tofree)) schedule_timeout_uninterruptible(1); @@ -1052,15 +1073,17 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) return NOTIFY_STOP; } - /* If we are not expecting a timeout, ignore it. */ + /* If we are not expecting a timeout, ignore it. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) return NOTIFY_OK; if (preaction_val != WDOG_PRETIMEOUT_NMI) return NOTIFY_OK; - /* If no one else handled the NMI, we assume it was the IPMI - watchdog. */ + /* + * If no one else handled the NMI, we assume it was the IPMI + * watchdog. + */ if (preop_val == WDOG_PREOP_PANIC) { /* On some machines, the heartbeat will give an error and not work unless we re-enable @@ -1082,7 +1105,7 @@ static int wdog_reboot_handler(struct notifier_block *this, unsigned long code, void *unused) { - static int reboot_event_handled = 0; + static int reboot_event_handled; if ((watchdog_user) && (!reboot_event_handled)) { /* Make sure we only do this once. */ @@ -1115,7 +1138,7 @@ static int wdog_panic_handler(struct notifier_block *this, unsigned long event, void *unused) { - static int panic_event_handled = 0; + static int panic_event_handled; /* On a panic, if we have a panic timeout, make sure to extend the watchdog timer to a reasonable value to complete the @@ -1125,7 +1148,7 @@ static int wdog_panic_handler(struct notifier_block *this, ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { /* Make sure we do this only once. */ panic_event_handled = 1; - + timeout = 255; pretimeout = 0; panic_halt_ipmi_set_timeout(); @@ -1151,8 +1174,7 @@ static void ipmi_smi_gone(int if_num) ipmi_unregister_watchdog(if_num); } -static struct ipmi_smi_watcher smi_watcher = -{ +static struct ipmi_smi_watcher smi_watcher = { .owner = THIS_MODULE, .new_smi = ipmi_new_smi, .smi_gone = ipmi_smi_gone diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index eba2883b630e..4f3cefa8eb0e 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 c645455c3fd1..7c8b62f162bf 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 60b934adea65..7f7e798c1384 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/mem.c b/drivers/char/mem.c index e83623ead441..934ffafedaea 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -364,6 +364,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) return 0; } +#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; @@ -384,6 +385,7 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) vma->vm_pgoff = pfn; return mmap_mem(file, vma); } +#endif #ifdef CONFIG_CRASH_DUMP /* @@ -422,6 +424,7 @@ static ssize_t read_oldmem(struct file *file, char __user *buf, extern long vread(char *buf, char *addr, unsigned long count); extern long vwrite(char *buf, char *addr, unsigned long count); +#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -626,6 +629,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, *ppos = p; return virtr + wrote; } +#endif #ifdef CONFIG_DEVPORT static ssize_t read_port(struct file * file, char __user * buf, @@ -803,6 +807,7 @@ static const struct file_operations mem_fops = { .get_unmapped_area = get_unmapped_area_mem, }; +#ifdef CONFIG_DEVKMEM static const struct file_operations kmem_fops = { .llseek = memory_lseek, .read = read_kmem, @@ -811,6 +816,7 @@ static const struct file_operations kmem_fops = { .open = open_kmem, .get_unmapped_area = get_unmapped_area_mem, }; +#endif static const struct file_operations null_fops = { .llseek = null_lseek, @@ -889,11 +895,13 @@ static int memory_open(struct inode * inode, struct file * filp) filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#ifdef CONFIG_DEVKMEM case 2: filp->f_op = &kmem_fops; filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#endif case 3: filp->f_op = &null_fops; break; @@ -942,7 +950,9 @@ static const struct { const struct file_operations *fops; } devlist[] = { /* list of minor devices */ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, +#ifdef CONFIG_DEVKMEM {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, +#endif {3, "null", S_IRUGO | S_IWUGO, &null_fops}, #ifdef CONFIG_DEVPORT {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 4d058dadbfcc..eaace0db0ff4 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -263,23 +263,26 @@ EXPORT_SYMBOL(misc_deregister); static int __init misc_init(void) { -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; + int err; - ent = create_proc_entry("misc", 0, NULL); - if (ent) - ent->proc_fops = &misc_proc_fops; +#ifdef CONFIG_PROC_FS + proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc"); + err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) - return PTR_ERR(misc_class); + goto fail_remove; - if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { - printk("unable to get major %d for misc devices\n", - MISC_MAJOR); - class_destroy(misc_class); - return -EIO; - } + err = -EIO; + if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) + goto fail_printk; return 0; + +fail_printk: + printk("unable to get major %d for misc devices\n", MISC_MAJOR); + class_destroy(misc_class); +fail_remove: + remove_proc_entry("misc", NULL); + return err; } subsys_initcall(misc_init); diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index e60a74c66e3d..192961fd7173 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -30,6 +30,8 @@ #include <linux/miscdevice.h> #include <linux/posix-timers.h> #include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/math64.h> #include <asm/uaccess.h> #include <asm/sn/addrs.h> @@ -74,9 +76,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 +85,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 +108,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 +124,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 +135,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 +146,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 +157,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 +172,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 +197,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 +218,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 @@ -366,8 +474,8 @@ static int sgi_clock_get(clockid_t clockid, struct timespec *tp) nsec = rtc_time() * sgi_clock_period + sgi_clock_offset.tv_nsec; - tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec) - + sgi_clock_offset.tv_sec; + *tp = ns_to_timespec(nsec); + tp->tv_sec += sgi_clock_offset.tv_sec; return 0; }; @@ -375,11 +483,11 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp) { u64 nsec; - u64 rem; + u32 rem; nsec = rtc_time() * sgi_clock_period; - sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem); + sgi_clock_offset.tv_sec = tp->tv_sec - div_u64_rem(nsec, NSEC_PER_SEC, &rem); if (rem <= tp->tv_nsec) sgi_clock_offset.tv_nsec = tp->tv_sec - rem; @@ -390,35 +498,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 +514,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,25 +599,53 @@ 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; } -#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC) -#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec) - /* Assumption: it_lock is already held with irq's disabled */ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) { @@ -547,9 +658,8 @@ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) return; } - ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period); - ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period); - return; + cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period); + cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period); } @@ -557,30 +667,33 @@ 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); sgi_timer_del(timr); - when = timespec_to_ns(new_setting->it_value); - period = timespec_to_ns(new_setting->it_interval); + when = timespec_to_ns(&new_setting->it_value); + period = timespec_to_ns(&new_setting->it_interval); if (when == 0) /* 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; getnstimeofday(&n); - now = timespec_to_ns(n); + now = timespec_to_ns(&n); if (when > now) when -= now; else @@ -604,47 +717,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 +773,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 +809,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 +831,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 +841,3 @@ out1: } module_init(mmtimer_init); - diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 64b7b2b18352..d57d3a61919b 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 000000000000..87d16ce57be7 --- /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/mspec.c b/drivers/char/mspec.c index ff146c2b08fd..fe2a95b5d3c0 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -180,7 +180,7 @@ mspec_close(struct vm_area_struct *vma) my_page = vdata->maddr[index]; vdata->maddr[index] = 0; if (!mspec_zero_block(my_page, PAGE_SIZE)) - uncached_free_page(my_page); + uncached_free_page(my_page, 1); else printk(KERN_WARNING "mspec_close(): " "failed to zero page %ld\n", my_page); @@ -209,7 +209,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) index = (address - vdata->vm_start) >> PAGE_SHIFT; maddr = (volatile unsigned long) vdata->maddr[index]; if (maddr == 0) { - maddr = uncached_alloc_page(numa_node_id()); + maddr = uncached_alloc_page(numa_node_id(), 1); if (maddr == 0) return NOPFN_OOM; @@ -218,7 +218,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) vdata->count++; vdata->maddr[index] = maddr; } else { - uncached_free_page(maddr); + uncached_free_page(maddr, 1); maddr = vdata->maddr[index]; } spin_unlock(&vdata->lock); @@ -367,7 +367,7 @@ mspec_init(void) int nasid; unsigned long phys; - scratch_page[nid] = uncached_alloc_page(nid); + scratch_page[nid] = uncached_alloc_page(nid, 1); if (scratch_page[nid] == 0) goto free_scratch_pages; phys = __pa(scratch_page[nid]); @@ -414,7 +414,7 @@ mspec_init(void) free_scratch_pages: for_each_node(nid) { if (scratch_page[nid] != 0) - uncached_free_page(scratch_page[nid]); + uncached_free_page(scratch_page[nid], 1); } return ret; } @@ -431,7 +431,7 @@ mspec_exit(void) for_each_node(nid) { if (scratch_page[nid] != 0) - uncached_free_page(scratch_page[nid]); + uncached_free_page(scratch_page[nid], 1); } } } diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 68c2e9234691..4b81a85c5b53 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 844171115954..41878a69203d 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 82bcfb9c839a..a35bfd7ee80e 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) { @@ -501,7 +499,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, __FILE__,__LINE__, count); /* This can happen if stuff comes in on the backup tty */ - if (n_hdlc == 0 || tty != n_hdlc->tty) + if (!n_hdlc || tty != n_hdlc->tty) return; /* verify line is using HDLC discipline */ @@ -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 6b918b80f73e..902169062332 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 0c09409fa45d..19105ec203f7 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 6a6843a0a674..66a0f931c66c 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 454d7324ba40..4a933d413423 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 5f291bf739a6..035084c07329 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/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 1f978ff87fa8..fa9d3c945f31 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -354,32 +354,6 @@ struct ipw_rx_packet { unsigned int channel_idx; }; -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw) -{ - return snprintf(p, limit, - "debug: initializing=%d\n" - "debug: tx_ready=%d\n" - "debug: tx_queued=%d\n" - "debug: rx_ready=%d\n" - "debug: rx_bytes_queued=%d\n" - "debug: blocking_rx=%d\n" - "debug: removed=%d\n" - "debug: hardware.shutting_down=%d\n" - "debug: to_setup=%d\n", - hw->initializing, - hw->tx_ready, - hw->tx_queued, - hw->rx_ready, - hw->rx_bytes_queued, - hw->blocking_rx, - hw->removed, - hw->shutting_down, - hw->to_setup); -} -#endif - static char *data_type(const unsigned char *buf, unsigned length) { struct nl_packet_header *hdr = (struct nl_packet_header *) buf; diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h index c83190ffb0e7..19ce5eb266b1 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.h +++ b/drivers/char/pcmcia/ipwireless/hardware.h @@ -58,7 +58,5 @@ void ipwireless_init_hardware_v1(struct ipw_hardware *hw, void *reboot_cb_data); void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); void ipwireless_sleep(unsigned int tenths); -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw); #endif diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index d793e68b3e0d..fe914d34f7f6 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -63,21 +63,6 @@ struct ipw_network { struct work_struct work_go_offline; }; - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *network) -{ - return snprintf(p, limit, - "debug: ppp_blocked=%d\n" - "debug: outgoing_packets_queued=%d\n" - "debug: network.shutting_down=%d\n", - network->ppp_blocked, - network->outgoing_packets_queued, - network->shutting_down); -} -#endif - static void notify_packet_sent(void *callback_data, unsigned int packet_length) { struct ipw_network *network = callback_data; diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h index b0e1e952fd14..ccacd26fc7ef 100644 --- a/drivers/char/pcmcia/ipwireless/network.h +++ b/drivers/char/pcmcia/ipwireless/network.h @@ -49,7 +49,4 @@ void ipwireless_ppp_close(struct ipw_network *net); int ipwireless_ppp_channel_index(struct ipw_network *net); int ipwireless_ppp_unit_number(struct ipw_network *net); -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *net); - #endif diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 4e84d233e5a2..1dd0e992c83d 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -189,20 +189,20 @@ typedef struct _mgslpc_info { u32 pending_bh; - int bh_running; - int bh_requested; + bool bh_running; + bool bh_requested; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ int dsr_chkcount; /* is floating */ int ri_chkcount; - int rx_enabled; - int rx_overflow; + bool rx_enabled; + bool rx_overflow; - int tx_enabled; - int tx_active; - int tx_aborting; + bool tx_enabled; + bool tx_active; + bool tx_aborting; u32 idle_mode; int if_mode; /* serial interface selection (RS-232, v.35 etc) */ @@ -216,12 +216,12 @@ typedef struct _mgslpc_info { unsigned char serial_signals; /* current serial signal states */ - char irq_occurred; /* for diagnostics use */ + bool irq_occurred; /* for diagnostics use */ char testing_irq; unsigned int init_error; /* startup error (DIAGS) */ char flag_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; @@ -402,8 +402,8 @@ static void hdlcdev_exit(MGSLPC_INFO *info); static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); -static BOOLEAN register_test(MGSLPC_INFO *info); -static BOOLEAN irq_test(MGSLPC_INFO *info); +static bool register_test(MGSLPC_INFO *info); +static bool irq_test(MGSLPC_INFO *info); static int adapter_test(MGSLPC_INFO *info); static int claim_resources(MGSLPC_INFO *info); @@ -411,7 +411,7 @@ static void release_resources(MGSLPC_INFO *info); static void mgslpc_add_device(MGSLPC_INFO *info); static void mgslpc_remove_device(MGSLPC_INFO *info); -static int rx_get_frame(MGSLPC_INFO *info); +static bool rx_get_frame(MGSLPC_INFO *info); static void rx_reset_buffers(MGSLPC_INFO *info); static int rx_alloc_buffers(MGSLPC_INFO *info); static void rx_free_buffers(MGSLPC_INFO *info); @@ -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) { @@ -719,7 +708,7 @@ static int mgslpc_resume(struct pcmcia_device *link) } -static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, +static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info, char *name, const char *routine) { #ifdef MGSLPC_PARANOIA_CHECK @@ -730,17 +719,17 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, if (!info) { printk(badinfo, name, routine); - return 1; + return true; } if (info->magic != MGSLPC_MAGIC) { printk(badmagic, name, routine); - return 1; + return true; } #else if (!info) - return 1; + return true; #endif - return 0; + return false; } @@ -752,16 +741,16 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, #define CMD_TXEOM BIT1 // transmit end message #define CMD_TXRESET BIT0 // transmit reset -static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel) +static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel) { int i = 0; /* wait for command completion */ while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { udelay(1); if (i++ == 1000) - return FALSE; + return false; } - return TRUE; + return true; } static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) @@ -825,8 +814,8 @@ static int bh_action(MGSLPC_INFO *info) if (!rc) { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; } spin_unlock_irqrestore(&info->lock,flags); @@ -846,7 +835,7 @@ static void bh_handler(struct work_struct *work) printk( "%s(%d):bh_handler(%s) entry\n", __FILE__,__LINE__,info->device_name); - info->bh_running = 1; + info->bh_running = true; while((action = bh_action(info)) != 0) { @@ -913,7 +902,7 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) /* no more free buffers */ issue_command(info, CHA, CMD_RXRESET); info->pending_bh |= BH_RECEIVE; - info->rx_overflow = 1; + info->rx_overflow = true; info->icount.buf_overrun++; return; } @@ -1032,8 +1021,8 @@ static void tx_done(MGSLPC_INFO *info) if (!info->tx_active) return; - info->tx_active = 0; - info->tx_aborting = 0; + info->tx_active = false; + info->tx_aborting = false; if (info->params.mode == MGSL_MODE_ASYNC) return; @@ -1047,7 +1036,7 @@ static void tx_done(MGSLPC_INFO *info) info->serial_signals &= ~SerialSignal_RTS; set_signals(info); } - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; } #if SYNCLINK_GENERIC_HDLC @@ -1081,7 +1070,7 @@ static void tx_ready(MGSLPC_INFO *info) return; } if (!info->tx_count) - info->tx_active = 0; + info->tx_active = false; } if (!info->tx_count) @@ -1261,7 +1250,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) { isr = read_reg16(info, CHA + ISR); if (isr & IRQ_TIMER) { - info->irq_occurred = 1; + info->irq_occurred = true; irq_disable(info, CHA, IRQ_TIMER); } @@ -1318,7 +1307,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,info->device_name); schedule_work(&info->task); - info->bh_requested = 1; + info->bh_requested = true; } spin_unlock(&info->lock); @@ -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 @@ -1990,7 +1980,7 @@ static int tx_abort(MGSLPC_INFO * info) * This results in underrun and abort transmission. */ info->tx_count = info->tx_put = info->tx_get = 0; - info->tx_aborting = TRUE; + info->tx_aborting = true; } spin_unlock_irqrestore(&info->lock,flags); return 0; @@ -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); @@ -2589,7 +2578,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2604,7 +2594,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -2622,7 +2612,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->lock, flags); @@ -3493,8 +3483,8 @@ static void rx_stop(MGSLPC_INFO *info) /* MODE:03 RAC Receiver Active, 0=inactive */ clear_reg_bits(info, CHA + MODE, BIT3); - info->rx_enabled = 0; - info->rx_overflow = 0; + info->rx_enabled = false; + info->rx_overflow = false; } static void rx_start(MGSLPC_INFO *info) @@ -3504,13 +3494,13 @@ static void rx_start(MGSLPC_INFO *info) __FILE__,__LINE__, info->device_name ); rx_reset_buffers(info); - info->rx_enabled = 0; - info->rx_overflow = 0; + info->rx_enabled = false; + info->rx_overflow = false; /* MODE:03 RAC Receiver Active, 1=active */ set_reg_bits(info, CHA + MODE, BIT3); - info->rx_enabled = 1; + info->rx_enabled = true; } static void tx_start(MGSLPC_INFO *info) @@ -3523,24 +3513,24 @@ static void tx_start(MGSLPC_INFO *info) /* If auto RTS enabled and RTS is inactive, then assert */ /* RTS and set a flag indicating that the driver should */ /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if (info->params.flags & HDLC_FLAG_AUTO_RTS) { get_signals(info); if (!(info->serial_signals & SerialSignal_RTS)) { info->serial_signals |= SerialSignal_RTS; set_signals(info); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } if (info->params.mode == MGSL_MODE_ASYNC) { if (!info->tx_active) { - info->tx_active = 1; + info->tx_active = true; tx_ready(info); } } else { - info->tx_active = 1; + info->tx_active = true; tx_ready(info); mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); @@ -3548,7 +3538,7 @@ static void tx_start(MGSLPC_INFO *info) } if (!info->tx_enabled) - info->tx_enabled = 1; + info->tx_enabled = true; } static void tx_stop(MGSLPC_INFO *info) @@ -3559,8 +3549,8 @@ static void tx_stop(MGSLPC_INFO *info) del_timer(&info->tx_timer); - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } /* Reset the adapter to a known state and prepare it for further use. @@ -3860,19 +3850,19 @@ static void rx_reset_buffers(MGSLPC_INFO *info) /* Attempt to return a received HDLC frame * Only frames received without errors are returned. * - * Returns 1 if frame returned, otherwise 0 + * Returns true if frame returned, otherwise false */ -static int rx_get_frame(MGSLPC_INFO *info) +static bool rx_get_frame(MGSLPC_INFO *info) { unsigned short status; RXBUF *buf; unsigned int framesize = 0; unsigned long flags; struct tty_struct *tty = info->tty; - int return_frame = 0; + bool return_frame = false; if (info->rx_frame_count == 0) - return 0; + return false; buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size)); @@ -3891,7 +3881,7 @@ static int rx_get_frame(MGSLPC_INFO *info) else if (!(status & BIT5)) { info->icount.rxcrc++; if (info->params.crc_type & HDLC_CRC_RETURN_EX) - return_frame = 1; + return_frame = true; } framesize = 0; #if SYNCLINK_GENERIC_HDLC @@ -3902,7 +3892,7 @@ static int rx_get_frame(MGSLPC_INFO *info) } #endif } else - return_frame = 1; + return_frame = true; if (return_frame) framesize = buf->count; @@ -3945,16 +3935,16 @@ static int rx_get_frame(MGSLPC_INFO *info) info->rx_get = 0; spin_unlock_irqrestore(&info->lock,flags); - return 1; + return true; } -static BOOLEAN register_test(MGSLPC_INFO *info) +static bool register_test(MGSLPC_INFO *info) { static unsigned char patterns[] = { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; static unsigned int count = ARRAY_SIZE(patterns); unsigned int i; - BOOLEAN rc = TRUE; + bool rc = true; unsigned long flags; spin_lock_irqsave(&info->lock,flags); @@ -3965,7 +3955,7 @@ static BOOLEAN register_test(MGSLPC_INFO *info) write_reg(info, XAD2, patterns[(i + 1) % count]); if ((read_reg(info, XAD1) != patterns[i]) || (read_reg(info, XAD2) != patterns[(i + 1) % count])) { - rc = FALSE; + rc = false; break; } } @@ -3974,7 +3964,7 @@ static BOOLEAN register_test(MGSLPC_INFO *info) return rc; } -static BOOLEAN irq_test(MGSLPC_INFO *info) +static bool irq_test(MGSLPC_INFO *info) { unsigned long end_time; unsigned long flags; @@ -3982,10 +3972,10 @@ static BOOLEAN irq_test(MGSLPC_INFO *info) spin_lock_irqsave(&info->lock,flags); reset_device(info); - info->testing_irq = TRUE; + info->testing_irq = true; hdlc_mode(info); - info->irq_occurred = FALSE; + info->irq_occurred = false; /* init hdlc mode */ @@ -4000,13 +3990,13 @@ static BOOLEAN irq_test(MGSLPC_INFO *info) msleep_interruptible(10); } - info->testing_irq = FALSE; + info->testing_irq = false; spin_lock_irqsave(&info->lock,flags); reset_device(info); spin_unlock_irqrestore(&info->lock,flags); - return info->irq_occurred ? TRUE : FALSE; + return info->irq_occurred; } static int adapter_test(MGSLPC_INFO *info) @@ -4079,7 +4069,7 @@ static void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = 0; + info->tx_active = false; info->tx_count = info->tx_put = info->tx_get = 0; spin_unlock_irqrestore(&info->lock,flags); diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 706ff34728f1..0a05c038ae6f 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/random.c b/drivers/char/random.c index f43c89f7c449..0cf98bd4f2d2 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -272,7 +272,7 @@ static int random_write_wakeup_thresh = 128; static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; -static DEFINE_PER_CPU(int, trickle_count) = 0; +static DEFINE_PER_CPU(int, trickle_count); /* * A pool of size .poolwords is stirred with a primitive polynomial @@ -370,17 +370,19 @@ static struct poolinfo { */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; #if 0 -static int debug = 0; +static int debug; module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ - fmt,\ - input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ - ## arg); } while (0) +#define DEBUG_ENT(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG "random %04d %04d %04d: " \ + fmt,\ + input_pool.entropy_count,\ + blocking_pool.entropy_count,\ + nonblocking_pool.entropy_count,\ + ## arg); } while (0) #else #define DEBUG_ENT(fmt, arg...) do {} while (0) #endif @@ -394,7 +396,7 @@ module_param(debug, bool, 0644); struct entropy_store; struct entropy_store { - /* mostly-read data: */ + /* read-only data: */ struct poolinfo *poolinfo; __u32 *pool; const char *name; @@ -402,7 +404,7 @@ struct entropy_store { struct entropy_store *pull; /* read-write data: */ - spinlock_t lock ____cacheline_aligned_in_smp; + spinlock_t lock; unsigned add_ptr; int entropy_count; int input_rotate; @@ -438,25 +440,26 @@ static struct entropy_store nonblocking_pool = { }; /* - * This function adds a byte into the entropy "pool". It does not + * This function adds bytes into the entropy "pool". It does not * update the entropy estimate. The caller should call - * credit_entropy_store if this is appropriate. + * credit_entropy_bits if this is appropriate. * * The pool is stirred with a primitive polynomial of the appropriate * degree, and then twisted. We twist by three bits at a time because * it's cheap to do so and helps slightly in the expected case where * the entropy is concentrated in the low-order bits. */ -static void __add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords, __u32 out[16]) +static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { static __u32 const twist_table[8] = { 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5; - int new_rotate, input_rotate; + unsigned long i, j, tap1, tap2, tap3, tap4, tap5; + int input_rotate; int wordmask = r->poolinfo->poolwords - 1; - __u32 w, next_w; + const char *bytes = in; + __u32 w; unsigned long flags; /* Taps are constant, so we can load them without holding r->lock. */ @@ -465,78 +468,76 @@ static void __add_entropy_words(struct entropy_store *r, const __u32 *in, tap3 = r->poolinfo->tap3; tap4 = r->poolinfo->tap4; tap5 = r->poolinfo->tap5; - next_w = *in++; spin_lock_irqsave(&r->lock, flags); - prefetch_range(r->pool, wordmask); input_rotate = r->input_rotate; - add_ptr = r->add_ptr; + i = r->add_ptr; - while (nwords--) { - w = rol32(next_w, input_rotate); - if (nwords > 0) - next_w = *in++; - i = add_ptr = (add_ptr - 1) & wordmask; - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - new_rotate = input_rotate + 14; - if (i) - new_rotate = input_rotate + 7; - input_rotate = new_rotate & 31; + /* mix one byte at a time to simplify size handling and churn faster */ + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31); + i = (i - 1) & wordmask; /* XOR in the various taps */ + w ^= r->pool[i]; w ^= r->pool[(i + tap1) & wordmask]; w ^= r->pool[(i + tap2) & wordmask]; w ^= r->pool[(i + tap3) & wordmask]; w ^= r->pool[(i + tap4) & wordmask]; w ^= r->pool[(i + tap5) & wordmask]; - w ^= r->pool[i]; + + /* Mix the result back in with a twist */ r->pool[i] = (w >> 3) ^ twist_table[w & 7]; + + /* + * Normally, we add 7 bits of rotation to the pool. + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + input_rotate += i ? 7 : 14; } r->input_rotate = input_rotate; - r->add_ptr = add_ptr; + r->add_ptr = i; - if (out) { - for (i = 0; i < 16; i++) { - out[i] = r->pool[add_ptr]; - add_ptr = (add_ptr - 1) & wordmask; - } - } + if (out) + for (j = 0; j < 16; j++) + ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; spin_unlock_irqrestore(&r->lock, flags); } -static inline void add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords) +static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) { - __add_entropy_words(r, in, nwords, NULL); + mix_pool_bytes_extract(r, in, bytes, NULL); } /* * Credit (or debit) the entropy store with n bits of entropy */ -static void credit_entropy_store(struct entropy_store *r, int nbits) +static void credit_entropy_bits(struct entropy_store *r, int nbits) { unsigned long flags; + if (!nbits) + return; + spin_lock_irqsave(&r->lock, flags); - if (r->entropy_count + nbits < 0) { - DEBUG_ENT("negative entropy/overflow (%d+%d)\n", - r->entropy_count, nbits); + DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); + r->entropy_count += nbits; + if (r->entropy_count < 0) { + DEBUG_ENT("negative entropy/overflow\n"); r->entropy_count = 0; - } else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) { + } else if (r->entropy_count > r->poolinfo->POOLBITS) r->entropy_count = r->poolinfo->POOLBITS; - } else { - r->entropy_count += nbits; - if (nbits) - DEBUG_ENT("added %d entropy credits to %s\n", - nbits, r->name); + + /* should we wake readers? */ + if (r == &input_pool && + r->entropy_count >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); } spin_unlock_irqrestore(&r->lock, flags); @@ -551,7 +552,7 @@ static void credit_entropy_store(struct entropy_store *r, int nbits) /* There is one of these per entropy source */ struct timer_rand_state { cycles_t last_time; - long last_delta,last_delta2; + long last_delta, last_delta2; unsigned dont_count_entropy:1; }; @@ -586,7 +587,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) sample.jiffies = jiffies; sample.cycles = get_cycles(); sample.num = num; - add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4); + mix_pool_bytes(&input_pool, &sample, sizeof(sample)); /* * Calculate number of bits of randomness we probably added. @@ -620,13 +621,9 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * Round down by 1 bit on general principles, * and limit entropy entimate to 12 bits. */ - credit_entropy_store(&input_pool, - min_t(int, fls(delta>>1), 11)); + credit_entropy_bits(&input_pool, + min_t(int, fls(delta>>1), 11)); } - - if(input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); - out: preempt_enable(); } @@ -677,7 +674,7 @@ void add_disk_randomness(struct gendisk *disk) * *********************************************************************/ -static ssize_t extract_entropy(struct entropy_store *r, void * buf, +static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int rsvd); /* @@ -704,10 +701,10 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) "(%d of %d requested)\n", r->name, bytes * 8, nbytes * 8, r->entropy_count); - bytes=extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - add_entropy_words(r, tmp, (bytes + 3) / 4); - credit_entropy_store(r, bytes*8); + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes); + credit_entropy_bits(r, bytes*8); } } @@ -744,13 +741,15 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, if (r->limit && nbytes + reserved >= r->entropy_count / 8) nbytes = r->entropy_count/8 - reserved; - if(r->entropy_count / 8 >= nbytes + reserved) + if (r->entropy_count / 8 >= nbytes + reserved) r->entropy_count -= nbytes*8; else r->entropy_count = reserved; - if (r->entropy_count < random_write_wakeup_thresh) + if (r->entropy_count < random_write_wakeup_thresh) { wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + } } DEBUG_ENT("debiting %d entropy credits from %s%s\n", @@ -764,45 +763,46 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, static void extract_buf(struct entropy_store *r, __u8 *out) { int i; - __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS]; + __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; + __u8 extract[64]; + + /* Generate a hash across the pool, 16 words (512 bits) at a time */ + sha_init(hash); + for (i = 0; i < r->poolinfo->poolwords; i += 16) + sha_transform(hash, (__u8 *)(r->pool + i), workspace); - sha_init(buf); /* - * As we hash the pool, we mix intermediate values of - * the hash back into the pool. This eliminates - * backtracking attacks (where the attacker knows - * the state of the pool plus the current outputs, and - * attempts to find previous ouputs), unless the hash - * function can be inverted. + * We mix the hash back into the pool to prevent backtracking + * attacks (where the attacker knows the state of the pool + * plus the current outputs, and attempts to find previous + * ouputs), unless the hash function can be inverted. By + * mixing at least a SHA1 worth of hash data back, we make + * brute-forcing the feedback as hard as brute-forcing the + * hash. */ - for (i = 0; i < r->poolinfo->poolwords; i += 16) { - /* hash blocks of 16 words = 512 bits */ - sha_transform(buf, (__u8 *)(r->pool + i), buf + 5); - /* feed back portion of the resulting hash */ - add_entropy_words(r, &buf[i % 5], 1); - } + mix_pool_bytes_extract(r, hash, sizeof(hash), extract); /* - * To avoid duplicates, we atomically extract a - * portion of the pool while mixing, and hash one - * final time. + * To avoid duplicates, we atomically extract a portion of the + * pool while mixing, and hash one final time. */ - __add_entropy_words(r, &buf[i % 5], 1, data); - sha_transform(buf, (__u8 *)data, buf + 5); + sha_transform(hash, extract, workspace); + memset(extract, 0, sizeof(extract)); + memset(workspace, 0, sizeof(workspace)); /* - * In case the hash function has some recognizable - * output pattern, we fold it in half. + * In case the hash function has some recognizable output + * pattern, we fold it in half. Thus, we always feed back + * twice as much data as we output. */ - - buf[0] ^= buf[3]; - buf[1] ^= buf[4]; - buf[2] ^= rol32(buf[2], 16); - memcpy(out, buf, EXTRACT_SIZE); - memset(buf, 0, sizeof(buf)); + hash[0] ^= hash[3]; + hash[1] ^= hash[4]; + hash[2] ^= rol32(hash[2], 16); + memcpy(out, hash, EXTRACT_SIZE); + memset(hash, 0, sizeof(hash)); } -static ssize_t extract_entropy(struct entropy_store *r, void * buf, +static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int reserved) { ssize_t ret = 0, i; @@ -872,7 +872,6 @@ void get_random_bytes(void *buf, int nbytes) { extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); } - EXPORT_SYMBOL(get_random_bytes); /* @@ -894,12 +893,11 @@ static void init_std_data(struct entropy_store *r) spin_unlock_irqrestore(&r->lock, flags); now = ktime_get_real(); - add_entropy_words(r, (__u32 *)&now, sizeof(now)/4); - add_entropy_words(r, (__u32 *)utsname(), - sizeof(*(utsname()))/4); + mix_pool_bytes(r, &now, sizeof(now)); + mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); } -static int __init rand_initialize(void) +static int rand_initialize(void) { init_std_data(&input_pool); init_std_data(&blocking_pool); @@ -940,7 +938,7 @@ void rand_initialize_disk(struct gendisk *disk) #endif static ssize_t -random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { ssize_t n, retval = 0, count = 0; @@ -1002,8 +1000,7 @@ random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) } static ssize_t -urandom_read(struct file * file, char __user * buf, - size_t nbytes, loff_t *ppos) +urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { return extract_entropy_user(&nonblocking_pool, buf, nbytes); } @@ -1038,16 +1035,15 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count) count -= bytes; p += bytes; - add_entropy_words(r, buf, (bytes + 3) / 4); + mix_pool_bytes(r, buf, bytes); cond_resched(); } return 0; } -static ssize_t -random_write(struct file * file, const char __user * buffer, - size_t count, loff_t *ppos) +static ssize_t random_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { size_t ret; struct inode *inode = file->f_path.dentry->d_inode; @@ -1064,9 +1060,7 @@ random_write(struct file * file, const char __user * buffer, return (ssize_t)count; } -static int -random_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int size, ent_count; int __user *p = (int __user *)arg; @@ -1074,8 +1068,8 @@ random_ioctl(struct inode * inode, struct file * file, switch (cmd) { case RNDGETENTCNT: - ent_count = input_pool.entropy_count; - if (put_user(ent_count, p)) + /* inherently racy, no point locking */ + if (put_user(input_pool.entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1083,13 +1077,7 @@ random_ioctl(struct inode * inode, struct file * file, return -EPERM; if (get_user(ent_count, p)) return -EFAULT; - credit_entropy_store(&input_pool, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) @@ -1104,39 +1092,45 @@ random_ioctl(struct inode * inode, struct file * file, size); if (retval < 0) return retval; - credit_entropy_store(&input_pool, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: /* Clear the entropy pool counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - init_std_data(&input_pool); - init_std_data(&blocking_pool); - init_std_data(&nonblocking_pool); + rand_initialize(); return 0; default: return -EINVAL; } } +static int random_fasync(int fd, struct file *filp, int on) +{ + return fasync_helper(fd, filp, on, &fasync); +} + +static int random_release(struct inode *inode, struct file *filp) +{ + return fasync_helper(-1, filp, 0, &fasync); +} + const struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, - .ioctl = random_ioctl, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .release = random_release, }; const struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, - .ioctl = random_ioctl, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .release = random_release, }; /*************************************************************** @@ -1157,7 +1151,6 @@ void generate_random_uuid(unsigned char uuid_out[16]) /* Set the UUID variant to DCE */ uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; } - EXPORT_SYMBOL(generate_random_uuid); /******************************************************************** @@ -1339,7 +1332,7 @@ ctl_table random_table[] = { #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) +static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) { __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; @@ -1487,8 +1480,8 @@ __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, */ memcpy(hash, saddr, 16); - hash[4]=((__force u16)sport << 16) + (__force u16)dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); + hash[4] = ((__force u16)sport << 16) + (__force u16)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; @@ -1538,10 +1531,10 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * Note that the words are placed into the starting vector, which is * then mixed with a partial MD4 over random data. */ - hash[0]=(__force u32)saddr; - hash[1]=(__force u32)daddr; - hash[2]=((__force u16)sport << 16) + (__force u16)dport; - hash[3]=keyptr->secret[11]; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; seq += keyptr->count; @@ -1556,10 +1549,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * Choosing a clock of 64 ns period is OK. (period of 274 s) */ seq += ktime_to_ns(ktime_get_real()) >> 6; -#if 0 - printk("init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif + return seq; } @@ -1582,14 +1572,15 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[12]; memcpy(hash, saddr, 16); hash[4] = (__force u32)dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); return twothirdsMD4Transform((const __u32 *)daddr, hash); } @@ -1617,13 +1608,9 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, seq += ktime_to_ns(ktime_get_real()); seq &= (1ull << 48) - 1; -#if 0 - printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif + return seq; } - EXPORT_SYMBOL(secure_dccp_sequence_number); #endif diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h index f4f837f86829..a03a538a3efb 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 0ce96670f979..412777cd1e68 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 dc3f005614a3..7f26cd7c815e 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 bf36959fc121..7b96e0814887 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 d8eb2bcbe015..d65ceb9a434a 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 4734e26e1ccd..ea21686c69a4 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 da276ed57b3f..4810b845cc21 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/rioroute.c b/drivers/char/rio/rioroute.c index 85091ff74d96..7a9df7dcf9a8 100644 --- a/drivers/char/rio/rioroute.c +++ b/drivers/char/rio/rioroute.c @@ -526,7 +526,7 @@ void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit) ** If RTA is not powered on, the tx packets will be ** unset, so go no further. */ - if (PortP->TxStart == 0) { + if (!PortP->TxStart) { rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); break; diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index 1cb8580a161d..c99354843be1 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 3f9d0a9ac36d..f073c710ab8d 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 f585bc8579e9..743dc80a9325 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/rocket_int.h b/drivers/char/rocket_int.h index b01d38125a8f..143cc432fdb2 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -55,7 +55,7 @@ static inline void sOutW(unsigned short port, unsigned short value) static inline void out32(unsigned short port, Byte_t *p) { - u32 value = le32_to_cpu(get_unaligned((__le32 *)p)); + u32 value = get_unaligned_le32(p); #ifdef ROCKET_DEBUG_IO printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); #endif diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 5c3142b6f1fc..5f80a9dff573 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -88,6 +88,7 @@ #ifdef CONFIG_SPARC32 #include <linux/pci.h> +#include <linux/jiffies.h> #include <asm/ebus.h> static unsigned long rtc_port; @@ -1068,10 +1069,8 @@ no_irq: } #ifdef CONFIG_PROC_FS - ent = create_proc_entry("driver/rtc", 0, NULL); - if (ent) - ent->proc_fops = &rtc_proc_fops; - else + ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); + if (!ent) printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); #endif @@ -1316,7 +1315,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * Once the read clears, read the RTC time (again via ioctl). Easy. */ - while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) + while (rtc_is_updating() != 0 && + time_before(jiffies, uip_watchdog + 2*HZ/100)) cpu_relax(); /* diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index df8cd0ca97eb..fd2db07a50fc 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 b9c1dba6bd01..8fe099a41065 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 1b75b0b7d542..53b3d44f8c06 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -63,16 +63,13 @@ static int scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) { char *desc_end; - __be32 from_buf; /* record event source address */ - from_buf = get_unaligned((__be32 *)event); - *src = be32_to_cpup(&from_buf); + *src = get_unaligned_be32(event); event += 4; /* move on to event code */ /* record the system controller's event code */ - from_buf = get_unaligned((__be32 *)event); - *code = be32_to_cpup(&from_buf); + *code = get_unaligned_be32(event); event += 4; /* move on to event arguments */ /* how many arguments are in the packet? */ @@ -86,8 +83,7 @@ scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) /* not an integer argument, so give up */ return -1; } - from_buf = get_unaligned((__be32 *)event); - *esp_code = be32_to_cpup(&from_buf); + *esp_code = get_unaligned_be32(event); event += 4; /* parse out the event description */ @@ -275,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; } @@ -289,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; } @@ -299,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 c03ad164c39a..58533de59027 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 4b5b5b78acb4..2ee4d9893757 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 874aaa08e956..d17be10c5d21 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 a6e1c9ba1217..f39f6fd89350 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 a3237d48a584..ac5080df2565 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -218,9 +218,9 @@ struct mgsl_struct { u32 pending_bh; - int bh_running; /* Protection from multiple */ + bool bh_running; /* Protection from multiple */ int isr_overflow; - int bh_requested; + bool bh_requested; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ @@ -250,12 +250,12 @@ struct mgsl_struct { int tx_holding_count; /* number of tx holding buffers waiting */ struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; - int rx_enabled; - int rx_overflow; - int rx_rcc_underrun; + bool rx_enabled; + bool rx_overflow; + bool rx_rcc_underrun; - int tx_enabled; - int tx_active; + bool tx_enabled; + bool tx_active; u32 idle_mode; u16 cmr_value; @@ -269,14 +269,14 @@ struct mgsl_struct { unsigned int io_base; /* base I/O address of adapter */ unsigned int io_addr_size; /* size of the I/O address range */ - int io_addr_requested; /* nonzero if I/O address requested */ + bool io_addr_requested; /* true if I/O address requested */ unsigned int irq_level; /* interrupt level */ unsigned long irq_flags; - int irq_requested; /* nonzero if IRQ requested */ + bool irq_requested; /* true if IRQ requested */ unsigned int dma_level; /* DMA channel */ - int dma_requested; /* nonzero if dma channel requested */ + bool dma_requested; /* true if dma channel requested */ u16 mbre_bit; u16 loopback_bits; @@ -286,27 +286,27 @@ struct mgsl_struct { unsigned char serial_signals; /* current serial signal states */ - int irq_occurred; /* for diagnostics use */ + bool irq_occurred; /* for diagnostics use */ unsigned int init_error; /* Initialization startup error (DIAGS) */ int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */ u32 last_mem_alloc; unsigned char* memory_base; /* shared memory address (PCI only) */ u32 phys_memory_base; - int shared_mem_requested; + bool shared_mem_requested; unsigned char* lcr_base; /* local config registers (PCI only) */ u32 phys_lcr_base; u32 lcr_offset; - int lcr_mem_requested; + bool lcr_mem_requested; u32 misc_ctrl_value; char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; - BOOLEAN loopmode_insert_requested; - BOOLEAN loopmode_send_done_requested; + bool loopmode_insert_requested; + bool loopmode_send_done_requested; struct _input_signal_events input_signal_events; @@ -752,10 +752,10 @@ static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int coun /* * Adapter diagnostic routines */ -static BOOLEAN mgsl_register_test( struct mgsl_struct *info ); -static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ); -static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ); -static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ); +static bool mgsl_register_test( struct mgsl_struct *info ); +static bool mgsl_irq_test( struct mgsl_struct *info ); +static bool mgsl_dma_test( struct mgsl_struct *info ); +static bool mgsl_memory_test( struct mgsl_struct *info ); static int mgsl_adapter_test( struct mgsl_struct *info ); /* @@ -770,8 +770,8 @@ static struct mgsl_struct* mgsl_allocate_device(void); * DMA buffer manupulation functions. */ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); -static int mgsl_get_rx_frame( struct mgsl_struct *info ); -static int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); +static bool mgsl_get_rx_frame( struct mgsl_struct *info ); +static bool mgsl_get_raw_rx_frame( struct mgsl_struct *info ); static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); static int num_free_tx_dma_buffers(struct mgsl_struct *info); @@ -791,7 +791,7 @@ static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); -static int load_next_tx_holding_buffer(struct mgsl_struct *info); +static bool load_next_tx_holding_buffer(struct mgsl_struct *info); static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); /* @@ -847,7 +847,7 @@ static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); static int mgsl_loopmode_send_done( struct mgsl_struct * info ); /* set non-zero on successful registration with PCI subsystem */ -static int pci_registered; +static bool pci_registered; /* * Global linked list of SyncLink devices @@ -1054,8 +1054,8 @@ static int mgsl_bh_action(struct mgsl_struct *info) if (!rc) { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; } spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -1079,7 +1079,7 @@ static void mgsl_bh_handler(struct work_struct *work) printk( "%s(%d):mgsl_bh_handler(%s) entry\n", __FILE__,__LINE__,info->device_name); - info->bh_running = 1; + info->bh_running = true; while((action = mgsl_bh_action(info)) != 0) { @@ -1113,7 +1113,7 @@ static void mgsl_bh_handler(struct work_struct *work) static void mgsl_bh_receive(struct mgsl_struct *info) { - int (*get_rx_frame)(struct mgsl_struct *info) = + bool (*get_rx_frame)(struct mgsl_struct *info) = (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); if ( debug_level >= DEBUG_LEVEL_BH ) @@ -1187,7 +1187,7 @@ static void mgsl_isr_receive_status( struct mgsl_struct *info ) usc_loopmode_active(info) ) { ++info->icount.rxabort; - info->loopmode_insert_requested = FALSE; + info->loopmode_insert_requested = false; /* clear CMR:13 to start echoing RxD to TxD */ info->cmr_value &= ~BIT13; @@ -1257,7 +1257,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) else info->icount.txunder++; - info->tx_active = 0; + info->tx_active = false; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; del_timer(&info->tx_timer); @@ -1267,7 +1267,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) info->serial_signals &= ~SerialSignal_RTS; usc_set_serial_signals( info ); } - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; } #if SYNCLINK_GENERIC_HDLC @@ -1403,7 +1403,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) usc_OutReg( info, SICR, (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) ); usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED ); - info->irq_occurred = 1; + info->irq_occurred = true; } } /* end of mgsl_isr_io_pin() */ @@ -1431,7 +1431,7 @@ static void mgsl_isr_transmit_data( struct mgsl_struct *info ) if ( info->xmit_cnt ) usc_load_txfifo( info ); else - info->tx_active = 0; + info->tx_active = false; if (info->xmit_cnt < WAKEUP_CHARS) info->pending_bh |= BH_TRANSMIT; @@ -1568,7 +1568,7 @@ static void mgsl_isr_misc( struct mgsl_struct *info ) /* schedule BH handler to restart receiver */ info->pending_bh |= BH_RECEIVE; - info->rx_rcc_underrun = 1; + info->rx_rcc_underrun = true; } usc_ClearIrqPendingBits( info, MISC ); @@ -1626,7 +1626,7 @@ static void mgsl_isr_receive_dma( struct mgsl_struct *info ) info->pending_bh |= BH_RECEIVE; if ( status & BIT3 ) { - info->rx_overflow = 1; + info->rx_overflow = true; info->icount.buf_overrun++; } @@ -1745,7 +1745,7 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,info->device_name); schedule_work(&info->task); - info->bh_requested = 1; + info->bh_requested = true; } spin_unlock(&info->irq_spinlock); @@ -2026,34 +2026,35 @@ 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; + struct mgsl_struct *info = tty->driver_data; unsigned long flags; + int ret = 0; - if ( debug_level >= DEBUG_LEVEL_INFO ) { - printk( "%s(%d):mgsl_put_char(%d) on %s\n", - __FILE__,__LINE__,ch,info->device_name); + if (debug_level >= DEBUG_LEVEL_INFO) { + printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n", + __FILE__, __LINE__, ch, info->device_name); } 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 ) { + 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); + 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) @@ -3303,7 +3309,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3317,7 +3324,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3335,7 +3342,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, spin_lock_irqsave(&info->irq_spinlock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->irq_spinlock, flags); @@ -4043,13 +4050,13 @@ static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) * * info pointer to device instance data * - * Return Value: 1 if next buffered tx request loaded + * Return Value: true if next buffered tx request loaded * into adapter's tx dma buffer, - * 0 otherwise + * false otherwise */ -static int load_next_tx_holding_buffer(struct mgsl_struct *info) +static bool load_next_tx_holding_buffer(struct mgsl_struct *info) { - int ret = 0; + bool ret = false; if ( info->tx_holding_count ) { /* determine if we have enough tx dma buffers @@ -4073,7 +4080,7 @@ static int load_next_tx_holding_buffer(struct mgsl_struct *info) /* restart transmit timer */ mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); - ret = 1; + ret = true; } } @@ -4119,7 +4126,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name, info->io_base); return -ENODEV; } - info->io_addr_requested = 1; + info->io_addr_requested = true; if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags, info->device_name, info ) < 0 ) { @@ -4127,7 +4134,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name, info->irq_level ); goto errout; } - info->irq_requested = 1; + info->irq_requested = true; if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) { @@ -4135,15 +4142,16 @@ static int mgsl_claim_resources(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name, info->phys_memory_base); goto errout; } - info->shared_mem_requested = 1; + info->shared_mem_requested = true; if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) { printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset); goto errout; } - info->lcr_mem_requested = 1; + 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 ); @@ -4156,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 */ @@ -4172,7 +4182,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) mgsl_release_resources( info ); return -ENODEV; } - info->dma_requested = 1; + info->dma_requested = true; /* ISA adapter uses bus master DMA */ set_dma_mode(info->dma_level,DMA_MODE_CASCADE); @@ -4200,12 +4210,12 @@ static void mgsl_release_resources(struct mgsl_struct *info) if ( info->irq_requested ) { free_irq(info->irq_level, info); - info->irq_requested = 0; + info->irq_requested = false; } if ( info->dma_requested ) { disable_dma(info->dma_level); free_dma(info->dma_level); - info->dma_requested = 0; + info->dma_requested = false; } mgsl_free_dma_buffers(info); mgsl_free_intermediate_rxbuffer_memory(info); @@ -4213,15 +4223,15 @@ static void mgsl_release_resources(struct mgsl_struct *info) if ( info->io_addr_requested ) { release_region(info->io_base,info->io_addr_size); - info->io_addr_requested = 0; + info->io_addr_requested = false; } if ( info->shared_mem_requested ) { release_mem_region(info->phys_memory_base,0x40000); - info->shared_mem_requested = 0; + info->shared_mem_requested = false; } if ( info->lcr_mem_requested ) { release_mem_region(info->phys_lcr_base + info->lcr_offset,128); - info->lcr_mem_requested = 0; + info->lcr_mem_requested = false; } if (info->memory_base){ iounmap(info->memory_base); @@ -4486,7 +4496,7 @@ static int __init synclink_init(void) if ((rc = pci_register_driver(&synclink_pci_driver)) < 0) printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); else - pci_registered = 1; + pci_registered = true; if ((rc = mgsl_init_tty()) < 0) goto error; @@ -4679,7 +4689,7 @@ static u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) static void usc_set_sdlc_mode( struct mgsl_struct *info ) { u16 RegValue; - int PreSL1660; + bool PreSL1660; /* * determine if the IUSC on the adapter is pre-SL1660. If @@ -4692,11 +4702,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info ) */ usc_OutReg(info,TMCR,0x1f); RegValue=usc_InReg(info,TMDR); - if ( RegValue == IUSC_PRE_SL1660 ) - PreSL1660 = 1; - else - PreSL1660 = 0; - + PreSL1660 = (RegValue == IUSC_PRE_SL1660); if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) { @@ -5382,9 +5388,9 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) int start_index; int end_index; int frame_start_index; - int start_of_frame_found = FALSE; - int end_of_frame_found = FALSE; - int reprogram_dma = FALSE; + bool start_of_frame_found = false; + bool end_of_frame_found = false; + bool reprogram_dma = false; DMABUFFERENTRY *buffer_list = info->rx_buffer_list; u32 phys_addr; @@ -5410,9 +5416,9 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) if ( !start_of_frame_found ) { - start_of_frame_found = TRUE; + start_of_frame_found = true; frame_start_index = end_index; - end_of_frame_found = FALSE; + end_of_frame_found = false; } if ( buffer_list[end_index].status ) @@ -5423,8 +5429,8 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) /* We want to leave the buffers for this frame intact. */ /* Move on to next possible frame. */ - start_of_frame_found = FALSE; - end_of_frame_found = TRUE; + start_of_frame_found = false; + end_of_frame_found = true; } /* advance to next buffer entry in linked list */ @@ -5439,8 +5445,8 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) /* completely screwed, reset all receive buffers! */ mgsl_reset_rx_dma_buffers( info ); frame_start_index = 0; - start_of_frame_found = FALSE; - reprogram_dma = TRUE; + start_of_frame_found = false; + reprogram_dma = true; break; } } @@ -5466,7 +5472,7 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) } while( start_index != end_index ); - reprogram_dma = TRUE; + reprogram_dma = true; } if ( reprogram_dma ) @@ -5536,9 +5542,9 @@ static void usc_stop_receiver( struct mgsl_struct *info ) usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); usc_RTCmd( info, RTCmd_PurgeRxFifo ); - info->rx_enabled = 0; - info->rx_overflow = 0; - info->rx_rcc_underrun = 0; + info->rx_enabled = false; + info->rx_overflow = false; + info->rx_rcc_underrun = false; } /* end of stop_receiver() */ @@ -5601,7 +5607,7 @@ static void usc_start_receiver( struct mgsl_struct *info ) usc_OutReg( info, CCSR, 0x1020 ); - info->rx_enabled = 1; + info->rx_enabled = true; } /* end of usc_start_receiver() */ @@ -5628,14 +5634,14 @@ static void usc_start_transmitter( struct mgsl_struct *info ) /* RTS and set a flag indicating that the driver should */ /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { usc_get_serial_signals( info ); if ( !(info->serial_signals & SerialSignal_RTS) ) { info->serial_signals |= SerialSignal_RTS; usc_set_serial_signals( info ); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } @@ -5699,11 +5705,11 @@ static void usc_start_transmitter( struct mgsl_struct *info ) mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); } - info->tx_active = 1; + info->tx_active = true; } if ( !info->tx_enabled ) { - info->tx_enabled = 1; + info->tx_enabled = true; if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) usc_EnableTransmitter(info,ENABLE_AUTO_CTS); else @@ -5735,8 +5741,8 @@ static void usc_stop_transmitter( struct mgsl_struct *info ) usc_DmaCmd( info, DmaCmd_ResetTxChannel ); usc_RTCmd( info, RTCmd_PurgeTxFifo ); - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } /* end of usc_stop_transmitter() */ @@ -6520,7 +6526,7 @@ static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) */ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) { - int Done = 0; + bool Done = false; DMABUFFERENTRY *pBufEntry; unsigned int Index; @@ -6534,7 +6540,7 @@ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int S if ( Index == EndIndex ) { /* This is the last buffer of the frame! */ - Done = 1; + Done = true; } /* reset current buffer for reuse */ @@ -6559,18 +6565,18 @@ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int S * receive DMA buffers. Only frames received without errors are returned. * * Arguments: info pointer to device extension - * Return Value: 1 if frame returned, otherwise 0 + * Return Value: true if frame returned, otherwise false */ -static int mgsl_get_rx_frame(struct mgsl_struct *info) +static bool mgsl_get_rx_frame(struct mgsl_struct *info) { unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; DMABUFFERENTRY *pBufEntry; unsigned int framesize = 0; - int ReturnCode = 0; + bool ReturnCode = false; unsigned long flags; struct tty_struct *tty = info->tty; - int return_frame = 0; + bool return_frame = false; /* * current_rx_buffer points to the 1st buffer of the next available @@ -6629,7 +6635,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) else { info->icount.rxcrc++; if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) - return_frame = 1; + return_frame = true; } framesize = 0; #if SYNCLINK_GENERIC_HDLC @@ -6640,7 +6646,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) } #endif } else - return_frame = 1; + return_frame = true; if ( return_frame ) { /* receive frame has no errors, get frame size. @@ -6719,7 +6725,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) /* Free the buffers used by this frame. */ mgsl_free_rx_frame_buffers( info, StartIndex, EndIndex ); - ReturnCode = 1; + ReturnCode = true; Cleanup: @@ -6758,15 +6764,15 @@ Cleanup: * last Rx DMA buffer and return that last portion of the frame. * * Arguments: info pointer to device extension - * Return Value: 1 if frame returned, otherwise 0 + * Return Value: true if frame returned, otherwise false */ -static int mgsl_get_raw_rx_frame(struct mgsl_struct *info) +static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info) { unsigned int CurrentIndex, NextIndex; unsigned short status; DMABUFFERENTRY *pBufEntry; unsigned int framesize = 0; - int ReturnCode = 0; + bool ReturnCode = false; unsigned long flags; struct tty_struct *tty = info->tty; @@ -6891,7 +6897,7 @@ static int mgsl_get_raw_rx_frame(struct mgsl_struct *info) /* Free the buffers used by this frame. */ mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); - ReturnCode = 1; + ReturnCode = true; } @@ -7000,15 +7006,15 @@ static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, * Performs a register test of the 16C32. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) +static bool mgsl_register_test( struct mgsl_struct *info ) { static unsigned short BitPatterns[] = { 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f }; static unsigned int Patterncount = ARRAY_SIZE(BitPatterns); unsigned int i; - BOOLEAN rc = TRUE; + bool rc = true; unsigned long flags; spin_lock_irqsave(&info->irq_spinlock,flags); @@ -7019,10 +7025,10 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) if ( (usc_InReg( info, SICR ) != 0) || (usc_InReg( info, IVR ) != 0) || (usc_InDmaReg( info, DIVR ) != 0) ){ - rc = FALSE; + rc = false; } - if ( rc == TRUE ){ + if ( rc ){ /* Write bit patterns to various registers but do it out of */ /* sync, then read back and verify values. */ @@ -7040,7 +7046,7 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) (usc_InReg( info, RCLR ) != BitPatterns[(i+3)%Patterncount]) || (usc_InReg( info, RSR ) != BitPatterns[(i+4)%Patterncount]) || (usc_InDmaReg( info, TBCR ) != BitPatterns[(i+5)%Patterncount]) ){ - rc = FALSE; + rc = false; break; } } @@ -7056,9 +7062,9 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) /* mgsl_irq_test() Perform interrupt test of the 16C32. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) +static bool mgsl_irq_test( struct mgsl_struct *info ) { unsigned long EndTime; unsigned long flags; @@ -7068,10 +7074,10 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) /* * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. - * The ISR sets irq_occurred to 1. + * The ISR sets irq_occurred to true. */ - info->irq_occurred = FALSE; + info->irq_occurred = false; /* Enable INTEN gate for ISA adapter (Port 6, Bit12) */ /* Enable INTEN (Port 6, Bit12) */ @@ -7097,10 +7103,7 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) usc_reset(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if ( !info->irq_occurred ) - return FALSE; - else - return TRUE; + return info->irq_occurred; } /* end of mgsl_irq_test() */ @@ -7111,16 +7114,16 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) * using single buffer DMA mode. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) +static bool mgsl_dma_test( struct mgsl_struct *info ) { unsigned short FifoLevel; unsigned long phys_addr; unsigned int FrameSize; unsigned int i; char *TmpPtr; - BOOLEAN rc = TRUE; + bool rc = true; unsigned short status=0; unsigned long EndTime; unsigned long flags; @@ -7233,7 +7236,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) for(;;) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } @@ -7289,7 +7292,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) for(;;) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } @@ -7309,7 +7312,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) } - if ( rc == TRUE ) + if ( rc ) { /* Enable 16C32 transmitter. */ @@ -7337,7 +7340,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } @@ -7348,13 +7351,13 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) } - if ( rc == TRUE ){ + if ( rc ){ /* CHECK FOR TRANSMIT ERRORS */ if ( status & (BIT5 + BIT1) ) - rc = FALSE; + rc = false; } - if ( rc == TRUE ) { + if ( rc ) { /* WAIT FOR RECEIVE COMPLETE */ /* Wait 100ms */ @@ -7364,7 +7367,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) status=info->rx_buffer_list[0].status; while ( status == 0 ) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } status=info->rx_buffer_list[0].status; @@ -7372,17 +7375,17 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) } - if ( rc == TRUE ) { + if ( rc ) { /* CHECK FOR RECEIVE ERRORS */ status = info->rx_buffer_list[0].status; if ( status & (BIT8 + BIT3 + BIT1) ) { /* receive error has occurred */ - rc = FALSE; + rc = false; } else { if ( memcmp( info->tx_buffer_list[0].virt_addr , info->rx_buffer_list[0].virt_addr, FrameSize ) ){ - rc = FALSE; + rc = false; } } } @@ -7445,9 +7448,9 @@ static int mgsl_adapter_test( struct mgsl_struct *info ) * Test the shared memory on a PCI adapter. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) +static bool mgsl_memory_test( struct mgsl_struct *info ) { static unsigned long BitPatterns[] = { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; @@ -7457,7 +7460,7 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) unsigned long * TestAddr; if ( info->bus_type != MGSL_BUS_TYPE_PCI ) - return TRUE; + return true; TestAddr = (unsigned long *)info->memory_base; @@ -7466,7 +7469,7 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) for ( i = 0 ; i < Patterncount ; i++ ) { *TestAddr = BitPatterns[i]; if ( *TestAddr != BitPatterns[i] ) - return FALSE; + return false; } /* Test address lines with incrementing pattern over */ @@ -7481,13 +7484,13 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) for ( i = 0 ; i < TestLimit ; i++ ) { if ( *TestAddr != i * 4 ) - return FALSE; + return false; TestAddr++; } memset( info->memory_base, 0, SHARED_MEM_ADDRESS_SIZE ); - return TRUE; + return true; } /* End Of mgsl_memory_test() */ @@ -7604,7 +7607,7 @@ static void mgsl_tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->irq_spinlock,flags); - info->tx_active = 0; + info->tx_active = false; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) @@ -7632,7 +7635,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info ) spin_lock_irqsave(&info->irq_spinlock,flags); if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { if (info->tx_active) - info->loopmode_send_done_requested = TRUE; + info->loopmode_send_done_requested = true; else usc_loopmode_send_done(info); } @@ -7646,7 +7649,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info ) */ static void usc_loopmode_send_done( struct mgsl_struct * info ) { - info->loopmode_send_done_requested = FALSE; + info->loopmode_send_done_requested = false; /* clear CMR:13 to 0 to start echoing RxData to TxData */ info->cmr_value &= ~BIT13; usc_OutReg(info, CMR, info->cmr_value); @@ -7668,7 +7671,7 @@ static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) */ static void usc_loopmode_insert_request( struct mgsl_struct * info ) { - info->loopmode_insert_requested = TRUE; + info->loopmode_insert_requested = true; /* enable RxAbort irq. On next RxAbort, clear CMR:13 to * begin repeating TxData on RxData (complete insertion) diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 3c89266c8255..2001b0e52dc6 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -117,7 +117,7 @@ static struct pci_driver pci_driver = { .remove = __devexit_p(remove_one), }; -static int pci_registered; +static bool pci_registered; /* * module configuration and status @@ -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); @@ -289,12 +289,12 @@ struct slgt_info { struct work_struct task; u32 pending_bh; - int bh_requested; - int bh_running; + bool bh_requested; + bool bh_running; int isr_overflow; - int irq_requested; /* nonzero if IRQ requested */ - int irq_occurred; /* for diagnostics use */ + bool irq_requested; /* true if IRQ requested */ + bool irq_occurred; /* for diagnostics use */ /* device configuration */ @@ -304,7 +304,7 @@ struct slgt_info { unsigned char __iomem * reg_addr; /* memory mapped registers address */ u32 phys_reg_addr; - int reg_addr_requested; + bool reg_addr_requested; MGSL_PARAMS params; /* communications parameters */ u32 idle_mode; @@ -315,11 +315,11 @@ struct slgt_info { /* device status */ - int rx_enabled; - int rx_restart; + bool rx_enabled; + bool rx_restart; - int tx_enabled; - int tx_active; + bool tx_enabled; + bool tx_active; unsigned char signals; /* serial signal states */ int init_error; /* initialization error */ @@ -329,7 +329,7 @@ struct slgt_info { char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; int dcd_chkcount; /* check counts to prevent */ @@ -467,8 +467,8 @@ static void rx_start(struct slgt_info *info); static void reset_rbufs(struct slgt_info *info); static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); static void rdma_reset(struct slgt_info *info); -static int rx_get_frame(struct slgt_info *info); -static int rx_get_buf(struct slgt_info *info); +static bool rx_get_frame(struct slgt_info *info); +static bool rx_get_buf(struct slgt_info *info); static void tx_start(struct slgt_info *info); static void tx_stop(struct slgt_info *info); @@ -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; } /* @@ -1968,8 +1994,8 @@ static int bh_action(struct slgt_info *info) rc = BH_STATUS; } else { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; rc = 0; } @@ -1988,7 +2014,7 @@ static void bh_handler(struct work_struct *work) if (!info) return; - info->bh_running = 1; + info->bh_running = true; while((action = bh_action(info))) { switch (action) { @@ -2158,7 +2184,7 @@ static void isr_serial(struct slgt_info *info) wr_reg16(info, SSR, status); /* clear pending */ - info->irq_occurred = 1; + info->irq_occurred = true; if (info->params.mode == MGSL_MODE_ASYNC) { if (status & IRQ_TXIDLE) { @@ -2225,7 +2251,7 @@ static void isr_rdma(struct slgt_info *info) if (status & (BIT5 + BIT4)) { DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); - info->rx_restart = 1; + info->rx_restart = true; } info->pending_bh |= BH_RECEIVE; } @@ -2276,14 +2302,14 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) info->icount.txok++; } - info->tx_active = 0; + info->tx_active = false; info->tx_count = 0; del_timer(&info->tx_timer); if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { info->signals &= ~SerialSignal_RTS; - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; set_signals(info); } @@ -2337,7 +2363,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); - info->irq_occurred = 1; + info->irq_occurred = true; for(i=0; i < info->port_count ; i++) { if (info->port_array[i] == NULL) continue; @@ -2374,7 +2400,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) !port->bh_requested) { DBGISR(("%s bh queued\n", port->device_name)); schedule_work(&port->task); - port->bh_requested = 1; + port->bh_requested = true; } } @@ -3110,7 +3136,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; DBGINFO(("%s block_til_ready\n", tty->driver->name)); @@ -3122,7 +3149,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3136,7 +3163,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->lock, flags); @@ -3321,9 +3348,9 @@ static int claim_resources(struct slgt_info *info) goto errout; } else - info->reg_addr_requested = 1; + 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)); @@ -3341,12 +3368,12 @@ static void release_resources(struct slgt_info *info) { if (info->irq_requested) { free_irq(info->irq_level, info); - info->irq_requested = 0; + info->irq_requested = false; } if (info->reg_addr_requested) { release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE); - info->reg_addr_requested = 0; + info->reg_addr_requested = false; } if (info->reg_addr) { @@ -3511,7 +3538,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev) port_array[0]->device_name, port_array[0]->irq_level)); } else { - port_array[0]->irq_requested = 1; + port_array[0]->irq_requested = true; adapter_test(port_array[0]); for (i=1 ; i < port_count ; i++) { port_array[i]->init_error = port_array[0]->init_error; @@ -3654,7 +3681,7 @@ static int __init slgt_init(void) printk("%s pci_register_driver error=%d\n", driver_name, rc); goto error; } - pci_registered = 1; + pci_registered = true; if (!slgt_device_list) printk("%s no devices found\n",driver_name); @@ -3812,8 +3839,8 @@ static void rx_stop(struct slgt_info *info) rdma_reset(info); - info->rx_enabled = 0; - info->rx_restart = 0; + info->rx_enabled = false; + info->rx_restart = false; } static void rx_start(struct slgt_info *info) @@ -3849,8 +3876,8 @@ static void rx_start(struct slgt_info *info) /* enable receiver */ wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1)); - info->rx_restart = 0; - info->rx_enabled = 1; + info->rx_restart = false; + info->rx_enabled = true; } static void tx_start(struct slgt_info *info) @@ -3858,11 +3885,11 @@ static void tx_start(struct slgt_info *info) if (!info->tx_enabled) { wr_reg16(info, TCR, (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2)); - info->tx_enabled = TRUE; + info->tx_enabled = true; } if (info->tx_count) { - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if (info->params.mode != MGSL_MODE_ASYNC) { if (info->params.flags & HDLC_FLAG_AUTO_RTS) { @@ -3870,7 +3897,7 @@ static void tx_start(struct slgt_info *info) if (!(info->signals & SerialSignal_RTS)) { info->signals |= SerialSignal_RTS; set_signals(info); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } @@ -3888,7 +3915,7 @@ static void tx_start(struct slgt_info *info) wr_reg16(info, SSR, IRQ_TXIDLE); } tdma_start(info); - info->tx_active = 1; + info->tx_active = true; } } @@ -3949,8 +3976,8 @@ static void tx_stop(struct slgt_info *info) reset_tbufs(info); - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } static void reset_port(struct slgt_info *info) @@ -4470,14 +4497,13 @@ static void reset_rbufs(struct slgt_info *info) /* * pass receive HDLC frame to upper layer * - * return 1 if frame available, otherwise 0 + * return true if frame available, otherwise false */ -static int rx_get_frame(struct slgt_info *info) +static bool rx_get_frame(struct slgt_info *info) { unsigned int start, end; unsigned short status; unsigned int framesize = 0; - int rc = 0; unsigned long flags; struct tty_struct *tty = info->tty; unsigned char addr_field = 0xff; @@ -4601,23 +4627,23 @@ check_again: } } free_rbufs(info, start, end); - rc = 1; + return true; cleanup: - return rc; + return false; } /* * pass receive buffer (RAW synchronous mode) to tty layer - * return 1 if buffer available, otherwise 0 + * return true if buffer available, otherwise false */ -static int rx_get_buf(struct slgt_info *info) +static bool rx_get_buf(struct slgt_info *info) { unsigned int i = info->rbuf_current; unsigned int count; if (!desc_complete(info->rbufs[i])) - return 0; + return false; count = desc_count(info->rbufs[i]); switch(info->params.mode) { case MGSL_MODE_MONOSYNC: @@ -4633,7 +4659,7 @@ static int rx_get_buf(struct slgt_info *info) ldisc_receive_buf(info->tty, info->rbufs[i].buf, info->flag_buf, count); free_rbufs(info, i, i); - return 1; + return true; } static void reset_tbufs(struct slgt_info *info) @@ -4758,7 +4784,7 @@ static int irq_test(struct slgt_info *info) /* assume failure */ info->init_error = DiagStatus_IrqFailure; - info->irq_occurred = FALSE; + info->irq_occurred = false; spin_unlock_irqrestore(&info->lock, flags); @@ -4891,7 +4917,7 @@ static void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = 0; + info->tx_active = false; info->tx_count = 0; spin_unlock_irqrestore(&info->lock,flags); diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index c96062ea72b4..bec54866e0bb 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -188,9 +188,9 @@ typedef struct _synclinkmp_info { u32 pending_bh; - int bh_running; /* Protection from multiple */ + bool bh_running; /* Protection from multiple */ int isr_overflow; - int bh_requested; + bool bh_requested; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ @@ -213,11 +213,11 @@ typedef struct _synclinkmp_info { unsigned char *tmp_rx_buf; unsigned int tmp_rx_buf_count; - int rx_enabled; - int rx_overflow; + bool rx_enabled; + bool rx_overflow; - int tx_enabled; - int tx_active; + bool tx_enabled; + bool tx_active; u32 idle_mode; unsigned char ie0_value; @@ -238,13 +238,13 @@ typedef struct _synclinkmp_info { unsigned int irq_level; /* interrupt level */ unsigned long irq_flags; - int irq_requested; /* nonzero if IRQ requested */ + bool irq_requested; /* true if IRQ requested */ MGSL_PARAMS params; /* communications parameters */ unsigned char serial_signals; /* current serial signal states */ - int irq_occurred; /* for diagnostics use */ + bool irq_occurred; /* for diagnostics use */ unsigned int init_error; /* Initialization startup error */ u32 last_mem_alloc; @@ -255,7 +255,7 @@ typedef struct _synclinkmp_info { unsigned char* sca_base; /* HD64570 SCA Memory address */ u32 phys_sca_base; u32 sca_offset; - int sca_base_requested; + bool sca_base_requested; unsigned char* lcr_base; /* local config registers (PCI only) */ u32 phys_lcr_base; @@ -265,12 +265,12 @@ typedef struct _synclinkmp_info { unsigned char* statctrl_base; /* status/control register memory */ u32 phys_statctrl_base; u32 statctrl_offset; - int sca_statctrl_requested; + bool sca_statctrl_requested; u32 misc_ctrl_value; char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; @@ -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); @@ -571,12 +571,12 @@ static void shutdown(SLMP_INFO *info); static void program_hw(SLMP_INFO *info); static void change_params(SLMP_INFO *info); -static int init_adapter(SLMP_INFO *info); -static int register_test(SLMP_INFO *info); -static int irq_test(SLMP_INFO *info); -static int loopback_test(SLMP_INFO *info); +static bool init_adapter(SLMP_INFO *info); +static bool register_test(SLMP_INFO *info); +static bool irq_test(SLMP_INFO *info); +static bool loopback_test(SLMP_INFO *info); static int adapter_test(SLMP_INFO *info); -static int memory_test(SLMP_INFO *info); +static bool memory_test(SLMP_INFO *info); static void reset_adapter(SLMP_INFO *info); static void reset_port(SLMP_INFO *info); @@ -587,7 +587,7 @@ static void rx_stop(SLMP_INFO *info); static void rx_start(SLMP_INFO *info); static void rx_reset_buffers(SLMP_INFO *info); static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last); -static int rx_get_frame(SLMP_INFO *info); +static bool rx_get_frame(SLMP_INFO *info); static void tx_start(SLMP_INFO *info); static void tx_stop(SLMP_INFO *info); @@ -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.... */ @@ -1473,7 +1490,7 @@ static inline int line_info(char *buf, SLMP_INFO *info) /* Called to print information about devices */ -int read_proc(char *page, char **start, off_t off, int count, +static int read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0, l; @@ -2024,7 +2041,7 @@ static void hdlcdev_exit(SLMP_INFO *info) /* Return next bottom half action to perform. * Return Value: BH action code or 0 if nothing to do. */ -int bh_action(SLMP_INFO *info) +static int bh_action(SLMP_INFO *info) { unsigned long flags; int rc = 0; @@ -2044,8 +2061,8 @@ int bh_action(SLMP_INFO *info) if (!rc) { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; } spin_unlock_irqrestore(&info->lock,flags); @@ -2055,7 +2072,7 @@ int bh_action(SLMP_INFO *info) /* Perform bottom half processing of work items queued by ISR. */ -void bh_handler(struct work_struct *work) +static void bh_handler(struct work_struct *work) { SLMP_INFO *info = container_of(work, SLMP_INFO, task); int action; @@ -2067,7 +2084,7 @@ void bh_handler(struct work_struct *work) printk( "%s(%d):%s bh_handler() entry\n", __FILE__,__LINE__,info->device_name); - info->bh_running = 1; + info->bh_running = true; while((action = bh_action(info)) != 0) { @@ -2100,7 +2117,7 @@ void bh_handler(struct work_struct *work) __FILE__,__LINE__,info->device_name); } -void bh_receive(SLMP_INFO *info) +static void bh_receive(SLMP_INFO *info) { if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_receive()\n", @@ -2109,7 +2126,7 @@ void bh_receive(SLMP_INFO *info) while( rx_get_frame(info) ); } -void bh_transmit(SLMP_INFO *info) +static void bh_transmit(SLMP_INFO *info) { struct tty_struct *tty = info->tty; @@ -2121,7 +2138,7 @@ void bh_transmit(SLMP_INFO *info) tty_wakeup(tty); } -void bh_status(SLMP_INFO *info) +static void bh_status(SLMP_INFO *info) { if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_status() entry\n", @@ -2133,7 +2150,7 @@ void bh_status(SLMP_INFO *info) info->cts_chkcount = 0; } -void isr_timer(SLMP_INFO * info) +static void isr_timer(SLMP_INFO * info) { unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; @@ -2152,14 +2169,14 @@ void isr_timer(SLMP_INFO * info) */ write_reg(info, (unsigned char)(timer + TMCS), 0); - info->irq_occurred = TRUE; + info->irq_occurred = true; if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_timer()\n", __FILE__,__LINE__,info->device_name); } -void isr_rxint(SLMP_INFO * info) +static void isr_rxint(SLMP_INFO * info) { struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; @@ -2218,7 +2235,7 @@ void isr_rxint(SLMP_INFO * info) /* * handle async rx data interrupts */ -void isr_rxrdy(SLMP_INFO * info) +static void isr_rxrdy(SLMP_INFO * info) { u16 status; unsigned char DataByte; @@ -2232,7 +2249,7 @@ void isr_rxrdy(SLMP_INFO * info) while((status = read_reg(info,CST0)) & BIT0) { int flag = 0; - int over = 0; + bool over = false; DataByte = read_reg(info,TRB); icount->rx++; @@ -2265,7 +2282,7 @@ void isr_rxrdy(SLMP_INFO * info) * reported immediately, and doesn't * affect the current character */ - over = 1; + over = true; } } } /* end of if (error) */ @@ -2318,14 +2335,14 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) info->icount.txok++; } - info->tx_active = 0; + info->tx_active = false; info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) { info->serial_signals &= ~SerialSignal_RTS; - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; set_signals(info); } @@ -2348,7 +2365,7 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) /* * handle tx status interrupts */ -void isr_txint(SLMP_INFO * info) +static void isr_txint(SLMP_INFO * info) { unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); @@ -2376,7 +2393,7 @@ void isr_txint(SLMP_INFO * info) /* * handle async tx data interrupts */ -void isr_txrdy(SLMP_INFO * info) +static void isr_txrdy(SLMP_INFO * info) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txrdy() tx_count=%d\n", @@ -2398,7 +2415,7 @@ void isr_txrdy(SLMP_INFO * info) if ( info->tx_count ) tx_load_fifo( info ); else { - info->tx_active = 0; + info->tx_active = false; info->ie0_value &= ~TXRDYE; write_reg(info, IE0, info->ie0_value); } @@ -2407,7 +2424,7 @@ void isr_txrdy(SLMP_INFO * info) info->pending_bh |= BH_TRANSMIT; } -void isr_rxdmaok(SLMP_INFO * info) +static void isr_rxdmaok(SLMP_INFO * info) { /* BIT7 = EOT (end of transfer) * BIT6 = EOM (end of message/frame) @@ -2424,7 +2441,7 @@ void isr_rxdmaok(SLMP_INFO * info) info->pending_bh |= BH_RECEIVE; } -void isr_rxdmaerror(SLMP_INFO * info) +static void isr_rxdmaerror(SLMP_INFO * info) { /* BIT5 = BOF (buffer overflow) * BIT4 = COF (counter overflow) @@ -2438,11 +2455,11 @@ void isr_rxdmaerror(SLMP_INFO * info) printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n", __FILE__,__LINE__,info->device_name,status); - info->rx_overflow = TRUE; + info->rx_overflow = true; info->pending_bh |= BH_RECEIVE; } -void isr_txdmaok(SLMP_INFO * info) +static void isr_txdmaok(SLMP_INFO * info) { unsigned char status_reg1 = read_reg(info, SR1); @@ -2460,7 +2477,7 @@ void isr_txdmaok(SLMP_INFO * info) write_reg(info, IE0, info->ie0_value); } -void isr_txdmaerror(SLMP_INFO * info) +static void isr_txdmaerror(SLMP_INFO * info) { /* BIT5 = BOF (buffer overflow) * BIT4 = COF (counter overflow) @@ -2477,7 +2494,7 @@ void isr_txdmaerror(SLMP_INFO * info) /* handle input serial signal changes */ -void isr_io_pin( SLMP_INFO *info, u16 status ) +static void isr_io_pin( SLMP_INFO *info, u16 status ) { struct mgsl_icount *icount; @@ -2691,7 +2708,7 @@ static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,port->device_name); schedule_work(&port->task); - port->bh_requested = 1; + port->bh_requested = true; } } @@ -3320,7 +3337,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3335,7 +3353,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3353,7 +3371,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->lock, flags); @@ -3413,7 +3431,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return retval; } -int alloc_dma_bufs(SLMP_INFO *info) +static int alloc_dma_bufs(SLMP_INFO *info) { unsigned short BuffersPerFrame; unsigned short BufferCount; @@ -3487,7 +3505,7 @@ int alloc_dma_bufs(SLMP_INFO *info) /* Allocate DMA buffers for the transmit and receive descriptor lists. */ -int alloc_buf_list(SLMP_INFO *info) +static int alloc_buf_list(SLMP_INFO *info) { unsigned int i; @@ -3546,7 +3564,7 @@ int alloc_buf_list(SLMP_INFO *info) /* Allocate the frame DMA buffers used by the specified buffer list. */ -int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) +static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) { int i; unsigned long phys_addr; @@ -3563,7 +3581,7 @@ int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex, return 0; } -void free_dma_bufs(SLMP_INFO *info) +static void free_dma_bufs(SLMP_INFO *info) { info->buffer_list = NULL; info->rx_buf_list = NULL; @@ -3573,7 +3591,7 @@ void free_dma_bufs(SLMP_INFO *info) /* allocate buffer large enough to hold max_frame_size. * This buffer is used to pass an assembled frame to the line discipline. */ -int alloc_tmp_rx_buf(SLMP_INFO *info) +static int alloc_tmp_rx_buf(SLMP_INFO *info) { info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); if (info->tmp_rx_buf == NULL) @@ -3581,13 +3599,13 @@ int alloc_tmp_rx_buf(SLMP_INFO *info) return 0; } -void free_tmp_rx_buf(SLMP_INFO *info) +static void free_tmp_rx_buf(SLMP_INFO *info) { kfree(info->tmp_rx_buf); info->tmp_rx_buf = NULL; } -int claim_resources(SLMP_INFO *info) +static int claim_resources(SLMP_INFO *info) { if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", @@ -3596,7 +3614,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->shared_mem_requested = 1; + info->shared_mem_requested = true; if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", @@ -3605,7 +3623,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->lcr_mem_requested = 1; + info->lcr_mem_requested = true; if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", @@ -3614,7 +3632,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->sca_base_requested = 1; + info->sca_base_requested = true; if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", @@ -3623,9 +3641,10 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->sca_statctrl_requested = 1; + 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 ); @@ -3633,7 +3652,7 @@ 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 ); @@ -3642,7 +3661,7 @@ 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 ); @@ -3651,7 +3670,8 @@ 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 ); @@ -3674,7 +3694,7 @@ errout: return -ENODEV; } -void release_resources(SLMP_INFO *info) +static void release_resources(SLMP_INFO *info) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):%s release_resources() entry\n", @@ -3682,24 +3702,24 @@ void release_resources(SLMP_INFO *info) if ( info->irq_requested ) { free_irq(info->irq_level, info); - info->irq_requested = 0; + info->irq_requested = false; } if ( info->shared_mem_requested ) { release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); - info->shared_mem_requested = 0; + info->shared_mem_requested = false; } if ( info->lcr_mem_requested ) { release_mem_region(info->phys_lcr_base + info->lcr_offset,128); - info->lcr_mem_requested = 0; + info->lcr_mem_requested = false; } if ( info->sca_base_requested ) { release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); - info->sca_base_requested = 0; + info->sca_base_requested = false; } if ( info->sca_statctrl_requested ) { release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); - info->sca_statctrl_requested = 0; + info->sca_statctrl_requested = false; } if (info->memory_base){ @@ -3730,7 +3750,7 @@ void release_resources(SLMP_INFO *info) /* Add the specified device instance data structure to the * global linked list of devices and increment the device count. */ -void add_device(SLMP_INFO *info) +static void add_device(SLMP_INFO *info) { info->next_device = NULL; info->line = synclinkmp_device_count; @@ -3853,7 +3873,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) return info; } -void device_init(int adapter_num, struct pci_dev *pdev) +static void device_init(int adapter_num, struct pci_dev *pdev) { SLMP_INFO *port_array[SCA_MAX_PORTS]; int port; @@ -3902,7 +3922,7 @@ void device_init(int adapter_num, struct pci_dev *pdev) port_array[0]->irq_level ); } else { - port_array[0]->irq_requested = 1; + port_array[0]->irq_requested = true; adapter_test(port_array[0]); } } @@ -4047,7 +4067,7 @@ module_exit(synclinkmp_exit); * The TxCLK and RxCLK signals are generated from the BRG and * the TxD is looped back to the RxD internally. */ -void enable_loopback(SLMP_INFO *info, int enable) +static void enable_loopback(SLMP_INFO *info, int enable) { if (enable) { /* MD2 (Mode Register 2) @@ -4094,7 +4114,7 @@ void enable_loopback(SLMP_INFO *info, int enable) * data_rate data rate of clock in bits per second * A data rate of 0 disables the AUX clock. */ -void set_rate( SLMP_INFO *info, u32 data_rate ) +static void set_rate( SLMP_INFO *info, u32 data_rate ) { u32 TMCValue; unsigned char BRValue; @@ -4140,7 +4160,7 @@ void set_rate( SLMP_INFO *info, u32 data_rate ) /* Disable receiver */ -void rx_stop(SLMP_INFO *info) +static void rx_stop(SLMP_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):%s rx_stop()\n", @@ -4155,13 +4175,13 @@ void rx_stop(SLMP_INFO *info) write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ write_reg(info, RXDMA + DIR, 0); /* disable Rx DMA interrupts */ - info->rx_enabled = 0; - info->rx_overflow = 0; + info->rx_enabled = false; + info->rx_overflow = false; } /* enable the receiver */ -void rx_start(SLMP_INFO *info) +static void rx_start(SLMP_INFO *info) { int i; @@ -4211,14 +4231,14 @@ void rx_start(SLMP_INFO *info) write_reg(info, CMD, RXENABLE); - info->rx_overflow = FALSE; - info->rx_enabled = 1; + info->rx_overflow = false; + info->rx_enabled = true; } /* Enable the transmitter and send a transmit frame if * one is loaded in the DMA buffers. */ -void tx_start(SLMP_INFO *info) +static void tx_start(SLMP_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):%s tx_start() tx_count=%d\n", @@ -4227,7 +4247,7 @@ void tx_start(SLMP_INFO *info) if (!info->tx_enabled ) { write_reg(info, CMD, TXRESET); write_reg(info, CMD, TXENABLE); - info->tx_enabled = TRUE; + info->tx_enabled = true; } if ( info->tx_count ) { @@ -4236,7 +4256,7 @@ void tx_start(SLMP_INFO *info) /* RTS and set a flag indicating that the driver should */ /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if (info->params.mode != MGSL_MODE_ASYNC) { @@ -4245,7 +4265,7 @@ void tx_start(SLMP_INFO *info) if ( !(info->serial_signals & SerialSignal_RTS) ) { info->serial_signals |= SerialSignal_RTS; set_signals( info ); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } @@ -4282,13 +4302,13 @@ void tx_start(SLMP_INFO *info) write_reg(info, IE0, info->ie0_value); } - info->tx_active = 1; + info->tx_active = true; } } /* stop the transmitter and DMA */ -void tx_stop( SLMP_INFO *info ) +static void tx_stop( SLMP_INFO *info ) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):%s tx_stop()\n", @@ -4308,14 +4328,14 @@ void tx_stop( SLMP_INFO *info ) info->ie0_value &= ~TXRDYE; write_reg(info, IE0, info->ie0_value); /* disable tx data interrupts */ - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } /* Fill the transmit FIFO until the FIFO is full or * there is no more data to load. */ -void tx_load_fifo(SLMP_INFO *info) +static void tx_load_fifo(SLMP_INFO *info) { u8 TwoBytes[2]; @@ -4364,7 +4384,7 @@ void tx_load_fifo(SLMP_INFO *info) /* Reset a port to a known state */ -void reset_port(SLMP_INFO *info) +static void reset_port(SLMP_INFO *info) { if (info->sca_base) { @@ -4388,7 +4408,7 @@ void reset_port(SLMP_INFO *info) /* Reset all the ports to a known state. */ -void reset_adapter(SLMP_INFO *info) +static void reset_adapter(SLMP_INFO *info) { int i; @@ -4400,7 +4420,7 @@ void reset_adapter(SLMP_INFO *info) /* Program port for asynchronous communications. */ -void async_mode(SLMP_INFO *info) +static void async_mode(SLMP_INFO *info) { unsigned char RegValue; @@ -4539,7 +4559,7 @@ void async_mode(SLMP_INFO *info) /* Program the SCA for HDLC communications. */ -void hdlc_mode(SLMP_INFO *info) +static void hdlc_mode(SLMP_INFO *info) { unsigned char RegValue; u32 DpllDivisor; @@ -4741,7 +4761,7 @@ void hdlc_mode(SLMP_INFO *info) /* Set the transmit HDLC idle mode */ -void tx_set_idle(SLMP_INFO *info) +static void tx_set_idle(SLMP_INFO *info) { unsigned char RegValue = 0xff; @@ -4761,7 +4781,7 @@ void tx_set_idle(SLMP_INFO *info) /* Query the adapter for the state of the V24 status (input) signals. */ -void get_signals(SLMP_INFO *info) +static void get_signals(SLMP_INFO *info) { u16 status = read_reg(info, SR3); u16 gpstatus = read_status_reg(info); @@ -4790,7 +4810,7 @@ void get_signals(SLMP_INFO *info) /* Set the state of DTR and RTS based on contents of * serial_signals member of device context. */ -void set_signals(SLMP_INFO *info) +static void set_signals(SLMP_INFO *info) { unsigned char RegValue; u16 EnableBit; @@ -4819,7 +4839,7 @@ void set_signals(SLMP_INFO *info) * and set the current buffer to the first buffer. This effectively * makes all buffers free and discards any data in buffers. */ -void rx_reset_buffers(SLMP_INFO *info) +static void rx_reset_buffers(SLMP_INFO *info) { rx_free_frame_buffers(info, 0, info->rx_buf_count - 1); } @@ -4830,16 +4850,16 @@ void rx_reset_buffers(SLMP_INFO *info) * first index of 1st receive buffer of frame * last index of last receive buffer of frame */ -void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) +static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) { - int done = 0; + bool done = false; while(!done) { /* reset current buffer for reuse */ info->rx_buf_list[first].status = 0xff; if (first == last) { - done = 1; + done = true; /* set new last rx descriptor address */ write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry); } @@ -4856,14 +4876,14 @@ void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int las /* Return a received frame from the receive DMA buffers. * Only frames received without errors are returned. * - * Return Value: 1 if frame returned, otherwise 0 + * Return Value: true if frame returned, otherwise false */ -int rx_get_frame(SLMP_INFO *info) +static bool rx_get_frame(SLMP_INFO *info) { unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; unsigned int framesize = 0; - int ReturnCode = 0; + bool ReturnCode = false; unsigned long flags; struct tty_struct *tty = info->tty; unsigned char addr_field = 0xff; @@ -5014,7 +5034,7 @@ CheckAgain: /* Free the buffers used by this frame. */ rx_free_frame_buffers( info, StartIndex, EndIndex ); - ReturnCode = 1; + ReturnCode = true; Cleanup: if ( info->rx_enabled && info->rx_overflow ) { @@ -5033,7 +5053,7 @@ Cleanup: /* load the transmit DMA buffer with data */ -void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) +static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) { unsigned short copy_count; unsigned int i = 0; @@ -5073,12 +5093,12 @@ void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) info->last_tx_buf = ++i; } -int register_test(SLMP_INFO *info) +static bool register_test(SLMP_INFO *info) { static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96}; static unsigned int count = ARRAY_SIZE(testval); unsigned int i; - int rc = TRUE; + bool rc = true; unsigned long flags; spin_lock_irqsave(&info->lock,flags); @@ -5101,7 +5121,7 @@ int register_test(SLMP_INFO *info) (read_reg(info, SA0) != testval[(i+2)%count]) || (read_reg(info, SA1) != testval[(i+3)%count]) ) { - rc = FALSE; + rc = false; break; } } @@ -5112,7 +5132,7 @@ int register_test(SLMP_INFO *info) return rc; } -int irq_test(SLMP_INFO *info) +static bool irq_test(SLMP_INFO *info) { unsigned long timeout; unsigned long flags; @@ -5124,7 +5144,7 @@ int irq_test(SLMP_INFO *info) /* assume failure */ info->init_error = DiagStatus_IrqFailure; - info->irq_occurred = FALSE; + info->irq_occurred = false; /* setup timer0 on SCA0 to interrupt */ @@ -5163,7 +5183,7 @@ int irq_test(SLMP_INFO *info) /* initialize individual SCA device (2 ports) */ -static int sca_init(SLMP_INFO *info) +static bool sca_init(SLMP_INFO *info) { /* set wait controller to single mem partition (low), no wait states */ write_reg(info, PABR0, 0); /* wait controller addr boundary 0 */ @@ -5199,12 +5219,12 @@ static int sca_init(SLMP_INFO *info) */ write_reg(info, ITCR, 0); - return TRUE; + return true; } /* initialize adapter hardware */ -int init_adapter(SLMP_INFO *info) +static bool init_adapter(SLMP_INFO *info) { int i; @@ -5257,20 +5277,20 @@ int init_adapter(SLMP_INFO *info) sca_init(info->port_array[0]); sca_init(info->port_array[2]); - return TRUE; + return true; } /* Loopback an HDLC frame to test the hardware * interrupt and DMA functions. */ -int loopback_test(SLMP_INFO *info) +static bool loopback_test(SLMP_INFO *info) { #define TESTFRAMESIZE 20 unsigned long timeout; u16 count = TESTFRAMESIZE; unsigned char buf[TESTFRAMESIZE]; - int rc = FALSE; + bool rc = false; unsigned long flags; struct tty_struct *oldtty = info->tty; @@ -5304,16 +5324,16 @@ int loopback_test(SLMP_INFO *info) msleep_interruptible(10); if (rx_get_frame(info)) { - rc = TRUE; + rc = true; break; } } /* verify received frame length and contents */ - if (rc == TRUE && - ( info->tmp_rx_buf_count != count || - memcmp(buf, info->tmp_rx_buf,count))) { - rc = FALSE; + if (rc && + ( info->tmp_rx_buf_count != count || + memcmp(buf, info->tmp_rx_buf,count))) { + rc = false; } spin_lock_irqsave(&info->lock,flags); @@ -5328,7 +5348,7 @@ int loopback_test(SLMP_INFO *info) /* Perform diagnostics on hardware */ -int adapter_test( SLMP_INFO *info ) +static int adapter_test( SLMP_INFO *info ) { unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) @@ -5390,7 +5410,7 @@ int adapter_test( SLMP_INFO *info ) /* Test the shared memory on a PCI adapter. */ -int memory_test(SLMP_INFO *info) +static bool memory_test(SLMP_INFO *info) { static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; @@ -5404,7 +5424,7 @@ int memory_test(SLMP_INFO *info) for ( i = 0 ; i < count ; i++ ) { *addr = testval[i]; if ( *addr != testval[i] ) - return FALSE; + return false; } /* Test address lines with incrementing pattern over */ @@ -5419,12 +5439,12 @@ int memory_test(SLMP_INFO *info) for ( i = 0 ; i < limit ; i++ ) { if ( *addr != i * 4 ) - return FALSE; + return false; addr++; } memset( info->memory_base, 0, SCA_MEM_SIZE ); - return TRUE; + return true; } /* Load data into PCI adapter shared memory. @@ -5442,7 +5462,7 @@ int memory_test(SLMP_INFO *info) * the write transation. This allows any pending DMA request to gain control * of the local bus in a timely fasion. */ -void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) +static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) { /* A load interval of 16 allows for 4 32-bit writes at */ /* 136ns each for a maximum latency of 542ns on the local bus.*/ @@ -5461,7 +5481,7 @@ void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned shor memcpy(dest, src, count % sca_pci_load_interval); } -void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) +static void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) { int i; int linecount; @@ -5496,7 +5516,7 @@ void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) /* called when HDLC frame times out * update stats and do tx completion processing */ -void tx_timeout(unsigned long context) +static void tx_timeout(unsigned long context) { SLMP_INFO *info = (SLMP_INFO*)context; unsigned long flags; @@ -5508,7 +5528,7 @@ void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = 0; + info->tx_active = false; info->tx_count = info->tx_put = info->tx_get = 0; spin_unlock_irqrestore(&info->lock,flags); @@ -5523,7 +5543,7 @@ void tx_timeout(unsigned long context) /* called to periodically check the DSR/RI modem signal input status */ -void status_timeout(unsigned long context) +static void status_timeout(unsigned long context) { u16 status = 0; SLMP_INFO *info = (SLMP_INFO*)context; @@ -5574,36 +5594,36 @@ void status_timeout(unsigned long context) } -unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) +static unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) { CALC_REGADDR(); return *RegAddr; } -void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) +static void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) { CALC_REGADDR(); *RegAddr = Value; } -u16 read_reg16(SLMP_INFO * info, unsigned char Addr) +static u16 read_reg16(SLMP_INFO * info, unsigned char Addr) { CALC_REGADDR(); return *((u16 *)RegAddr); } -void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) +static void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) { CALC_REGADDR(); *((u16 *)RegAddr) = Value; } -unsigned char read_status_reg(SLMP_INFO * info) +static unsigned char read_status_reg(SLMP_INFO * info) { unsigned char *RegAddr = (unsigned char *)info->statctrl_base; return *RegAddr; } -void write_control_reg(SLMP_INFO * info) +static void write_control_reg(SLMP_INFO * info) { unsigned char *RegAddr = (unsigned char *)info->statctrl_base; *RegAddr = info->port_array[0]->ctrlreg_value; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index de60e1ea4fb3..9e9bad8bdcf4 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -196,6 +196,48 @@ static struct sysrq_key_op sysrq_showlocks_op = { #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) #endif +#ifdef CONFIG_SMP +static DEFINE_SPINLOCK(show_lock); + +static void showacpu(void *dummy) +{ + unsigned long flags; + + /* Idle CPUs have no interesting backtrace. */ + if (idle_cpu(smp_processor_id())) + return; + + spin_lock_irqsave(&show_lock, flags); + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_stack(NULL, NULL); + spin_unlock_irqrestore(&show_lock, flags); +} + +static void sysrq_showregs_othercpus(struct work_struct *dummy) +{ + smp_call_function(showacpu, NULL, 0, 0); +} + +static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); + +static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) +{ + struct pt_regs *regs = get_irq_regs(); + if (regs) { + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_regs(regs); + } + schedule_work(&sysrq_showallcpus); +} + +static struct sysrq_key_op sysrq_showallcpus_op = { + .handler = sysrq_handle_showallcpus, + .help_msg = "aLlcpus", + .action_msg = "Show backtrace of all active CPUs", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + static void sysrq_handle_showregs(int key, struct tty_struct *tty) { struct pt_regs *regs = get_irq_regs(); @@ -271,8 +313,7 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(struct work_struct *ignored) { - out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], - GFP_KERNEL, 0); + out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0); } static DECLARE_WORK(moom_work, moom_callback); @@ -341,7 +382,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_kill_op, /* i */ NULL, /* j */ &sysrq_SAK_op, /* k */ +#ifdef CONFIG_SMP + &sysrq_showallcpus_op, /* l */ +#else NULL, /* l */ +#endif &sysrq_showmem_op, /* m */ &sysrq_unrt_op, /* n */ /* o: This will often be registered as 'Off' at init time */ diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index ce5ebe3b168f..663cd15d7c78 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -426,7 +426,7 @@ static int tosh_probe(void) int i,major,minor,day,year,month,flag; unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 }; SMMRegisters regs; - void __iomem *bios = ioremap(0xf0000, 0x10000); + void __iomem *bios = ioremap_cache(0xf0000, 0x10000); if (!bios) return -ENOMEM; @@ -520,12 +520,11 @@ static int __init toshiba_init(void) { struct proc_dir_entry *pde; - pde = create_proc_entry("toshiba", 0, NULL); + pde = proc_create("toshiba", 0, NULL, &proc_toshiba_fops); if (!pde) { misc_deregister(&tosh_device); return -ENOMEM; } - pde->proc_fops = &proc_toshiba_fops; } #endif diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 8f3f7620f95a..3738cfa209ff 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -23,7 +23,7 @@ if TCG_TPM config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on PNPACPI + depends on PNP ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible @@ -32,7 +32,6 @@ config TCG_TIS config TCG_NSC tristate "National Semiconductor TPM Interface" - depends on PNPACPI ---help--- If you have a TPM security chip from National Semiconductor say Yes and it will be accessible from within Linux. To @@ -48,7 +47,7 @@ config TCG_ATMEL config TCG_INFINEON tristate "Infineon Technologies TPM Interface" - depends on PNPACPI + depends on PNP ---help--- If you have a TPM security chip from Infineon Technologies (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 6313326bc41f..ab18c1e7b115 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -264,7 +264,7 @@ static const struct tpm_vendor_specific tpm_nsc = { static struct platform_device *pdev = NULL; -static void __devexit tpm_nsc_remove(struct device *dev) +static void tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if ( chip ) { diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 7722466e052f..3582f43345a8 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -11,6 +11,7 @@ #include <linux/audit.h> #include <linux/file.h> +#include <linux/fdtable.h> #include <linux/tty.h> struct tty_audit_buf { @@ -92,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); - audit_log_n_untrustedstring(ab, buf->valid, buf->data); + audit_log_n_untrustedstring(ab, buf->data, buf->valid); audit_log_end(ab); } buf->valid = 0; @@ -151,14 +152,9 @@ void tty_audit_fork(struct signal_struct *sig) /** * tty_audit_push_task - Flush task's pending audit data */ -void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) +void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) { struct tty_audit_buf *buf; - /* FIXME I think this is correct. Check against netlink once that is - * I really need to read this code more closely. But that's for - * another patch. - */ - unsigned int sessionid = audit_get_sessionid(tsk); spin_lock_irq(&tsk->sighand->siglock); buf = tsk->signal->tty_audit_buf; @@ -238,6 +234,10 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, if (unlikely(size == 0)) return; + if (tty->driver->type == TTY_DRIVER_TYPE_PTY + && tty->driver->subtype == PTY_TYPE_MASTER) + return; + buf = tty_audit_buf_get(tty); if (!buf) return; @@ -300,53 +300,3 @@ void tty_audit_push(struct tty_struct *tty) tty_audit_buf_put(buf); } } - -/** - * tty_audit_opening - A TTY is being opened. - * - * As a special hack, tasks that close all their TTYs and open new ones - * are assumed to be system daemons (e.g. getty) and auditing is - * automatically disabled for them. - */ -void tty_audit_opening(void) -{ - int disable; - - disable = 1; - spin_lock_irq(¤t->sighand->siglock); - if (current->signal->audit_tty == 0) - disable = 0; - spin_unlock_irq(¤t->sighand->siglock); - if (!disable) - return; - - task_lock(current); - if (current->files) { - struct fdtable *fdt; - unsigned i; - - /* - * We don't take a ref to the file, so we must hold ->file_lock - * instead. - */ - spin_lock(¤t->files->file_lock); - fdt = files_fdtable(current->files); - for (i = 0; i < fdt->max_fds; i++) { - struct file *filp; - - filp = fcheck_files(current->files, i); - if (filp && is_tty(filp)) { - disable = 0; - break; - } - } - spin_unlock(¤t->files->file_lock); - } - task_unlock(current); - if (!disable) - return; - - spin_lock_irq(¤t->sighand->siglock); - current->signal->audit_tty = 0; - spin_unlock_irq(¤t->sighand->siglock); -} diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4d3c7018f0c3..49c1a2267a55 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -78,6 +78,7 @@ #include <linux/tty_flip.h> #include <linux/devpts_fs.h> #include <linux/file.h> +#include <linux/fdtable.h> #include <linux/console.h> #include <linux/timer.h> #include <linux/ctype.h> @@ -91,7 +92,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 +137,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 +149,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 +1105,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); @@ -1180,11 +1176,10 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (*str == ',') str++; if (*str == '\0') - str = 0; - - if (tty_line >= 0 && tty_line <= p->num && p->poll_init && - !p->poll_init(p, tty_line, str)) { + str = NULL; + 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 +1200,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 +1253,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 +1270,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 +1283,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 +1296,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 +1308,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 +1410,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 +1448,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 +1486,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 +1511,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 +1637,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(¤t->sighand->siglock); @@ -1648,7 +1660,6 @@ void disassociate_ctty(int on_exit) put_pid(old_pgrp); } mutex_unlock(&tty_mutex); - unlock_kernel(); return; } if (tty_pgrp) { @@ -1667,10 +1678,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 +1697,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 +1706,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 +1729,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 +1763,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 +1800,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 +1822,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 +1914,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 +1967,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 +2120,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 +2151,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 +2456,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 +2636,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 +2734,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; } @@ -2755,7 +2773,6 @@ got_driver: __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); - tty_audit_opening(); return 0; } @@ -2777,29 +2794,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); @@ -2812,23 +2813,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); - if (!retval) { - tty_audit_opening(); + 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 @@ -2885,6 +2882,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; @@ -2900,6 +2898,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; @@ -2907,6 +2906,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; @@ -2992,6 +2992,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; @@ -3009,10 +3011,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: @@ -3073,10 +3086,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; } @@ -3134,6 +3150,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 @@ -3147,13 +3184,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; } /** @@ -3165,7 +3207,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) @@ -3173,6 +3215,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; @@ -3195,8 +3238,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; @@ -3240,10 +3285,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; } /** @@ -3263,18 +3314,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 @@ -3289,8 +3340,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); @@ -3299,7 +3350,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 @@ -3316,7 +3367,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); @@ -3340,7 +3391,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; } @@ -3348,20 +3399,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) @@ -3370,21 +3419,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; @@ -3442,7 +3498,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); @@ -3454,11 +3509,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 @@ -3487,8 +3544,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; } @@ -3515,8 +3572,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; } @@ -3566,8 +3623,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 */ @@ -3773,19 +3829,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; /** @@ -3868,37 +3937,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); @@ -3961,9 +4001,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); @@ -4039,14 +4076,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 f95a80b2265f..b1a757a5ee27 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 8de6b95aeb84..3d3e1c2b310f 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/viotape.c b/drivers/char/viotape.c index db7a731e2362..58aad63831f4 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -249,6 +249,7 @@ static int proc_viotape_open(struct inode *inode, struct file *file) } static const struct file_operations proc_viotape_operations = { + .owner = THIS_MODULE, .open = proc_viotape_open, .read = seq_read, .llseek = seq_lseek, @@ -915,7 +916,6 @@ static struct vio_driver viotape_driver = { int __init viotap_init(void) { int ret; - struct proc_dir_entry *e; if (!firmware_has_feature(FW_FEATURE_ISERIES)) return -ENODEV; @@ -968,11 +968,8 @@ int __init viotap_init(void) if (ret) goto unreg_class; - e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viotape_operations; - } + proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL, + &proc_viotape_operations); return 0; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 9b58b894f823..e458b08139af 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char, vc->vc_size_row * nr); } @@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(s, vc->vc_video_erase_char, 2 * step); + scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step); } static void do_update_region(struct vc_data *vc, unsigned long start, int count) @@ -400,7 +400,7 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, * Bit 7 : blink */ { - u8 a = vc->vc_color; + u8 a = _color; if (!vc->vc_can_do_color) return _intensity | (_italic ? 2 : 0) | @@ -434,6 +434,7 @@ static void update_attr(struct vc_data *vc) vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; + vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, false, false) << 8) | ' '; } /* Note: inverting the screen twice should revert to the original state */ @@ -908,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)) @@ -2054,6 +2061,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co unsigned long draw_from = 0, draw_to = 0; struct vc_data *vc; unsigned char vc_attr; + struct vt_notifier_param param; uint8_t rescan; uint8_t inverse; uint8_t width; @@ -2113,6 +2121,8 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co if (IS_FG(vc)) hide_cursor(vc); + param.vc = vc; + while (!tty->stopped && count) { int orig = *buf; c = orig; @@ -2201,6 +2211,11 @@ rescan_last_byte: tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; } + param.c = tc; + if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE, + ¶m) == NOTIFY_STOP) + continue; + /* If the original code was a control character we * only allow a glyph to be displayed if the code is * not normally used (such as for cursor movement) or @@ -2532,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: @@ -2551,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 @@ -2606,6 +2624,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = -EINVAL; break; } + unlock_kernel(); return ret; } @@ -2623,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) @@ -3820,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)) { @@ -3985,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 e6f89e8b9258..3211afd9d57e 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/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index c159ae64eeb2..5f076aef74fa 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -69,6 +69,15 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE the frequency statically to the highest frequency supported by the CPU. +config CPU_FREQ_DEFAULT_GOV_POWERSAVE + bool "powersave" + depends on EMBEDDED + select CPU_FREQ_GOV_POWERSAVE + help + Use the CPUFreq governor 'powersave' as default. This sets + the frequency statically to the lowest frequency supported by + the CPU. + config CPU_FREQ_DEFAULT_GOV_USERSPACE bool "userspace" select CPU_FREQ_GOV_USERSPACE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 35a26a3e5f68..7fce038fa57e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -118,9 +118,11 @@ static void handle_update(struct work_struct *work); static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); static struct srcu_notifier_head cpufreq_transition_notifier_list; +static bool init_cpufreq_transition_notifier_list_called; static int __init init_cpufreq_transition_notifier_list(void) { srcu_init_notifier_head(&cpufreq_transition_notifier_list); + init_cpufreq_transition_notifier_list_called = true; return 0; } pure_initcall(init_cpufreq_transition_notifier_list); @@ -216,7 +218,7 @@ static void cpufreq_debug_disable_ratelimit(void) } void cpufreq_debug_printk(unsigned int type, const char *prefix, - const char *fmt, ...) + const char *fmt, ...) { char s[256]; va_list args; @@ -378,7 +380,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor) /** * cpufreq_parse_governor - parse a governor string */ -static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, +static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, struct cpufreq_governor **governor) { int err = -EINVAL; @@ -446,7 +448,7 @@ extern struct sysdev_class cpu_sysdev_class; #define show_one(file_name, object) \ static ssize_t show_##file_name \ -(struct cpufreq_policy * policy, char *buf) \ +(struct cpufreq_policy *policy, char *buf) \ { \ return sprintf (buf, "%u\n", policy->object); \ } @@ -465,7 +467,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, */ #define store_one(file_name, object) \ static ssize_t store_##file_name \ -(struct cpufreq_policy * policy, const char *buf, size_t count) \ +(struct cpufreq_policy *policy, const char *buf, size_t count) \ { \ unsigned int ret = -EINVAL; \ struct cpufreq_policy new_policy; \ @@ -490,8 +492,8 @@ store_one(scaling_max_freq,max); /** * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware */ -static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, - char *buf) +static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, + char *buf) { unsigned int cur_freq = __cpufreq_get(policy->cpu); if (!cur_freq) @@ -503,8 +505,7 @@ static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, /** * show_scaling_governor - show the current policy for the specified CPU */ -static ssize_t show_scaling_governor (struct cpufreq_policy * policy, - char *buf) +static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) { if(policy->policy == CPUFREQ_POLICY_POWERSAVE) return sprintf(buf, "powersave\n"); @@ -519,8 +520,8 @@ static ssize_t show_scaling_governor (struct cpufreq_policy * policy, /** * store_scaling_governor - store policy for the specified CPU */ -static ssize_t store_scaling_governor (struct cpufreq_policy * policy, - const char *buf, size_t count) +static ssize_t store_scaling_governor(struct cpufreq_policy *policy, + const char *buf, size_t count) { unsigned int ret = -EINVAL; char str_governor[16]; @@ -554,7 +555,7 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, /** * show_scaling_driver - show the cpufreq driver currently loaded */ -static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf) +static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) { return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name); } @@ -562,8 +563,8 @@ static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf) /** * show_scaling_available_governors - show the available CPUfreq governors */ -static ssize_t show_scaling_available_governors (struct cpufreq_policy *policy, - char *buf) +static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, + char *buf) { ssize_t i = 0; struct cpufreq_governor *t; @@ -582,15 +583,13 @@ out: i += sprintf(&buf[i], "\n"); return i; } -/** - * show_affected_cpus - show the CPUs affected by each transition - */ -static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf) + +static ssize_t show_cpus(cpumask_t mask, char *buf) { ssize_t i = 0; unsigned int cpu; - for_each_cpu_mask(cpu, policy->cpus) { + for_each_cpu_mask(cpu, mask) { if (i) i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); @@ -601,8 +600,27 @@ static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf) return i; } +/** + * show_related_cpus - show the CPUs affected by each transition even if + * hw coordination is in use + */ +static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) +{ + if (cpus_empty(policy->related_cpus)) + return show_cpus(policy->cpus, buf); + return show_cpus(policy->related_cpus, buf); +} + +/** + * show_affected_cpus - show the CPUs affected by each transition + */ +static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) +{ + return show_cpus(policy->cpus, buf); +} + static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, - const char *buf, size_t count) + const char *buf, size_t count) { unsigned int freq = 0; unsigned int ret; @@ -645,18 +663,20 @@ define_one_ro(cpuinfo_max_freq); define_one_ro(scaling_available_governors); define_one_ro(scaling_driver); define_one_ro(scaling_cur_freq); +define_one_ro(related_cpus); define_one_ro(affected_cpus); define_one_rw(scaling_min_freq); define_one_rw(scaling_max_freq); define_one_rw(scaling_governor); define_one_rw(scaling_setspeed); -static struct attribute * default_attrs[] = { +static struct attribute *default_attrs[] = { &cpuinfo_min_freq.attr, &cpuinfo_max_freq.attr, &scaling_min_freq.attr, &scaling_max_freq.attr, &affected_cpus.attr, + &related_cpus.attr, &scaling_governor.attr, &scaling_driver.attr, &scaling_available_governors.attr, @@ -667,10 +687,10 @@ static struct attribute * default_attrs[] = { #define to_policy(k) container_of(k,struct cpufreq_policy,kobj) #define to_attr(a) container_of(a,struct freq_attr,attr) -static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf) +static ssize_t show(struct kobject *kobj, struct attribute *attr ,char *buf) { - struct cpufreq_policy * policy = to_policy(kobj); - struct freq_attr * fattr = to_attr(attr); + struct cpufreq_policy *policy = to_policy(kobj); + struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; policy = cpufreq_cpu_get(policy->cpu); if (!policy) @@ -691,11 +711,11 @@ no_policy: return ret; } -static ssize_t store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct cpufreq_policy * policy = to_policy(kobj); - struct freq_attr * fattr = to_attr(attr); + struct cpufreq_policy *policy = to_policy(kobj); + struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; policy = cpufreq_cpu_get(policy->cpu); if (!policy) @@ -716,9 +736,9 @@ no_policy: return ret; } -static void cpufreq_sysfs_release(struct kobject * kobj) +static void cpufreq_sysfs_release(struct kobject *kobj) { - struct cpufreq_policy * policy = to_policy(kobj); + struct cpufreq_policy *policy = to_policy(kobj); dprintk("last reference is dropped\n"); complete(&policy->kobj_unregister); } @@ -740,7 +760,7 @@ static struct kobj_type ktype_cpufreq = { * * Adds the cpufreq interface for a CPU device. */ -static int cpufreq_add_dev (struct sys_device * sys_dev) +static int cpufreq_add_dev(struct sys_device *sys_dev) { unsigned int cpu = sys_dev->id; int ret = 0; @@ -800,7 +820,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = cpufreq_driver->init(policy); if (ret) { dprintk("initialization failed\n"); - unlock_policy_rwsem_write(cpu); goto err_out; } policy->user_policy.min = policy->cpuinfo.min_freq; @@ -823,7 +842,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* check for existing affected CPUs. They may not be aware * of it due to CPU Hotplug. */ - managed_policy = cpufreq_cpu_get(j); + managed_policy = cpufreq_cpu_get(j); // FIXME: Where is this released? What about error paths? if (unlikely(managed_policy)) { /* Set proper policy_cpu */ @@ -842,14 +861,11 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = sysfs_create_link(&sys_dev->kobj, &managed_policy->kobj, "cpufreq"); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } cpufreq_debug_enable_ratelimit(); ret = 0; - unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; /* call driver->exit() */ } } @@ -859,33 +875,26 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj, "cpufreq"); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } + /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; while ((drv_attr) && (*drv_attr)) { ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } drv_attr++; } - if (cpufreq_driver->get){ + if (cpufreq_driver->get) { ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } } - if (cpufreq_driver->target){ + if (cpufreq_driver->target) { ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } } spin_lock_irqsave(&cpufreq_driver_lock, flags); @@ -907,10 +916,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) cpu_sys_dev = get_cpu_sysdev(j); ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, "cpufreq"); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_unregister; - } } policy->governor = NULL; /* to assure that the starting sequence is @@ -950,6 +957,7 @@ err_out_driver_exit: cpufreq_driver->exit(policy); err_out: + unlock_policy_rwsem_write(cpu); kfree(policy); nomem_out: @@ -967,7 +975,7 @@ module_out: * Caller should already have policy_rwsem in write mode for this CPU. * This routine frees the rwsem before returning. */ -static int __cpufreq_remove_dev (struct sys_device * sys_dev) +static int __cpufreq_remove_dev(struct sys_device *sys_dev) { unsigned int cpu = sys_dev->id; unsigned long flags; @@ -1071,7 +1079,7 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev) } -static int cpufreq_remove_dev (struct sys_device * sys_dev) +static int cpufreq_remove_dev(struct sys_device *sys_dev) { unsigned int cpu = sys_dev->id; int retval; @@ -1138,7 +1146,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) cpufreq_cpu_put(policy); } - return (ret_freq); + return ret_freq; } EXPORT_SYMBOL(cpufreq_quick_get); @@ -1149,7 +1157,7 @@ static unsigned int __cpufreq_get(unsigned int cpu) unsigned int ret_freq = 0; if (!cpufreq_driver->get) - return (ret_freq); + return ret_freq; ret_freq = cpufreq_driver->get(cpu); @@ -1163,7 +1171,7 @@ static unsigned int __cpufreq_get(unsigned int cpu) } } - return (ret_freq); + return ret_freq; } /** @@ -1190,7 +1198,7 @@ unsigned int cpufreq_get(unsigned int cpu) out_policy: cpufreq_cpu_put(policy); out: - return (ret_freq); + return ret_freq; } EXPORT_SYMBOL(cpufreq_get); @@ -1199,7 +1207,7 @@ EXPORT_SYMBOL(cpufreq_get); * cpufreq_suspend - let the low level driver prepare for suspend */ -static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) +static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) { int cpu = sysdev->id; int ret = 0; @@ -1221,22 +1229,18 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) return -EINVAL; /* only handle each CPU group once */ - if (unlikely(cpu_policy->cpu != cpu)) { - cpufreq_cpu_put(cpu_policy); - return 0; - } + if (unlikely(cpu_policy->cpu != cpu)) + goto out; if (cpufreq_driver->suspend) { ret = cpufreq_driver->suspend(cpu_policy, pmsg); if (ret) { printk(KERN_ERR "cpufreq: suspend failed in ->suspend " "step on CPU %u\n", cpu_policy->cpu); - cpufreq_cpu_put(cpu_policy); - return ret; + goto out; } } - if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) goto out; @@ -1270,7 +1274,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) out: cpufreq_cpu_put(cpu_policy); - return 0; + return ret; } /** @@ -1281,7 +1285,7 @@ out: * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are * restored. */ -static int cpufreq_resume(struct sys_device * sysdev) +static int cpufreq_resume(struct sys_device *sysdev) { int cpu = sysdev->id; int ret = 0; @@ -1302,18 +1306,15 @@ static int cpufreq_resume(struct sys_device * sysdev) return -EINVAL; /* only handle each CPU group once */ - if (unlikely(cpu_policy->cpu != cpu)) { - cpufreq_cpu_put(cpu_policy); - return 0; - } + if (unlikely(cpu_policy->cpu != cpu)) + goto fail; if (cpufreq_driver->resume) { ret = cpufreq_driver->resume(cpu_policy); if (ret) { printk(KERN_ERR "cpufreq: resume failed in ->resume " "step on CPU %u\n", cpu_policy->cpu); - cpufreq_cpu_put(cpu_policy); - return ret; + goto fail; } } @@ -1353,6 +1354,7 @@ static int cpufreq_resume(struct sys_device * sysdev) out: schedule_work(&cpu_policy->update); +fail: cpufreq_cpu_put(cpu_policy); return ret; } @@ -1386,6 +1388,8 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) { int ret; + WARN_ON(!init_cpufreq_transition_notifier_list_called); + switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: ret = srcu_notifier_chain_register( @@ -1848,7 +1852,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_debug_enable_ratelimit(); } - return (ret); + return ret; } EXPORT_SYMBOL_GPL(cpufreq_register_driver); diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 13fe06b94b0a..88d2f44fba48 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -35,12 +35,12 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_powersave = { +struct cpufreq_governor cpufreq_gov_powersave = { .name = "powersave", .governor = cpufreq_governor_powersave, .owner = THIS_MODULE, }; - +EXPORT_SYMBOL(cpufreq_gov_powersave); static int __init cpufreq_gov_powersave_init(void) { @@ -58,5 +58,9 @@ MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'"); MODULE_LICENSE("GPL"); +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE +fs_initcall(cpufreq_gov_powersave_init); +#else module_init(cpufreq_gov_powersave_init); +#endif module_exit(cpufreq_gov_powersave_exit); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 070421a5480e..ae70d63a8b26 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -114,7 +114,7 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) stat->freq_table[i]); } if (len >= PAGE_SIZE) - return len; + return PAGE_SIZE; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); @@ -131,8 +131,12 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", stat->trans_table[i*stat->max_state+j]); } + if (len >= PAGE_SIZE) + break; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); } + if (len >= PAGE_SIZE) + return PAGE_SIZE; return len; } CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table); @@ -284,7 +288,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, if (!stat) return 0; - old_index = freq_table_get_index(stat, freq->old); + old_index = stat->last_index; new_index = freq_table_get_index(stat, freq->new); cpufreq_stats_update(freq->cpu); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 2b382990fe58..6e6c3c4aea6b 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -67,7 +67,7 @@ config EDAC_E7XXX E7205, E7500, E7501 and E7505 server chipsets. config EDAC_E752X - tristate "Intel e752x (e7520, e7525, e7320)" + tristate "Intel e752x (e7520, e7525, e7320) and 3100" depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG help Support for error detection and correction on the Intel diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index f22075410591..2b95f1a3edfc 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -17,6 +17,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define AMD76X_REVISION " Ver: 2.0.2 " __DATE__ @@ -344,6 +345,9 @@ static struct pci_driver amd76x_driver = { static int __init amd76x_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&amd76x_driver); } @@ -358,3 +362,6 @@ module_exit(amd76x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); MODULE_DESCRIPTION("MC support for AMD 76x memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 6eb434749cd5..c94a0eb492cb 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -29,6 +29,7 @@ #define EDAC_MOD_STR "e752x_edac" static int force_function_unhide; +static int sysbus_parity = -1; static struct edac_pci_ctl_info *e752x_pci; @@ -62,6 +63,14 @@ static struct edac_pci_ctl_info *e752x_pci; #define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 #endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ +#ifndef PCI_DEVICE_ID_INTEL_3100_0 +#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0 +#endif /* PCI_DEVICE_ID_INTEL_3100_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR +#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1 +#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */ + #define E752X_NR_CSROWS 8 /* number of csrows */ /* E752X register addresses - device 0 function 0 */ @@ -152,6 +161,12 @@ static struct edac_pci_ctl_info *e752x_pci; /* error syndrome register (16b) */ #define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ +/* 3100 IMCH specific register addresses - device 0 function 1 */ +#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */ +#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */ +#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */ +#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */ + /* ICH5R register addresses - device 30 function 0 */ #define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ #define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ @@ -160,7 +175,8 @@ static struct edac_pci_ctl_info *e752x_pci; enum e752x_chips { E7520 = 0, E7525 = 1, - E7320 = 2 + E7320 = 2, + I3100 = 3 }; struct e752x_pvt { @@ -185,8 +201,10 @@ struct e752x_dev_info { struct e752x_error_info { u32 ferr_global; u32 nerr_global; - u8 hi_ferr; - u8 hi_nerr; + u32 nsi_ferr; /* 3100 only */ + u32 nsi_nerr; /* 3100 only */ + u8 hi_ferr; /* all but 3100 */ + u8 hi_nerr; /* all but 3100 */ u16 sysbus_ferr; u16 sysbus_nerr; u8 buf_ferr; @@ -215,6 +233,10 @@ static const struct e752x_dev_info e752x_devs[] = { .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, .ctl_name = "E7320"}, + [I3100] = { + .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR, + .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0, + .ctl_name = "3100"}, }; static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, @@ -402,7 +424,7 @@ static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, static char *global_message[11] = { "PCI Express C1", "PCI Express C", "PCI Express B1", "PCI Express B", "PCI Express A1", "PCI Express A", - "DMA Controler", "HUB Interface", "System Bus", + "DMA Controler", "HUB or NS Interface", "System Bus", "DRAM Controler", "Internal Buffer" }; @@ -455,6 +477,63 @@ static inline void hub_error(int fatal, u8 errors, int *error_found, do_hub_error(fatal, errors); } +#define NSI_FATAL_MASK 0x0c080081 +#define NSI_NON_FATAL_MASK 0x23a0ba64 +#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK) + +static char *nsi_message[30] = { + "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */ + "", /* reserved */ + "NSI Parity Error", /* bit 2, non-fatal */ + "", /* reserved */ + "", /* reserved */ + "Correctable Error Message", /* bit 5, non-fatal */ + "Non-Fatal Error Message", /* bit 6, non-fatal */ + "Fatal Error Message", /* bit 7, fatal */ + "", /* reserved */ + "Receiver Error", /* bit 9, non-fatal */ + "", /* reserved */ + "Bad TLP", /* bit 11, non-fatal */ + "Bad DLLP", /* bit 12, non-fatal */ + "REPLAY_NUM Rollover", /* bit 13, non-fatal */ + "", /* reserved */ + "Replay Timer Timeout", /* bit 15, non-fatal */ + "", /* reserved */ + "", /* reserved */ + "", /* reserved */ + "Data Link Protocol Error", /* bit 19, fatal */ + "", /* reserved */ + "Poisoned TLP", /* bit 21, non-fatal */ + "", /* reserved */ + "Completion Timeout", /* bit 23, non-fatal */ + "Completer Abort", /* bit 24, non-fatal */ + "Unexpected Completion", /* bit 25, non-fatal */ + "Receiver Overflow", /* bit 26, fatal */ + "Malformed TLP", /* bit 27, fatal */ + "", /* reserved */ + "Unsupported Request" /* bit 29, non-fatal */ +}; + +static void do_nsi_error(int fatal, u32 errors) +{ + int i; + + for (i = 0; i < 30; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "%sError %s\n", + fatal_message[fatal], nsi_message[i]); + } +} + +static inline void nsi_error(int fatal, u32 errors, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_nsi_error(fatal, errors); +} + static char *membuf_message[4] = { "Internal PMWB to DRAM parity", "Internal PMWB to System Bus Parity", @@ -546,6 +625,31 @@ static void e752x_check_hub_interface(struct e752x_error_info *info, } } +static void e752x_check_ns_interface(struct e752x_error_info *info, + int *error_found, int handle_error) +{ + u32 stat32; + + stat32 = info->nsi_ferr; + if (stat32 & NSI_ERR_MASK) { /* Error, so process */ + if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */ + nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, + handle_error); + if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */ + nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, + handle_error); + } + stat32 = info->nsi_nerr; + if (stat32 & NSI_ERR_MASK) { + if (stat32 & NSI_FATAL_MASK) + nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, + handle_error); + if (stat32 & NSI_NON_FATAL_MASK) + nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, + handle_error); + } +} + static void e752x_check_sysbus(struct e752x_error_info *info, int *error_found, int handle_error) { @@ -653,7 +757,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); if (info->ferr_global) { - pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_read_config_dword(dev, I3100_NSI_FERR, + &info->nsi_ferr); + info->hi_ferr = 0; + } else { + pci_read_config_byte(dev, E752X_HI_FERR, + &info->hi_ferr); + info->nsi_ferr = 0; + } pci_read_config_word(dev, E752X_SYSBUS_FERR, &info->sysbus_ferr); pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); @@ -669,10 +781,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, &info->dram_retr_add); + /* ignore the reserved bits just in case */ if (info->hi_ferr & 0x7f) pci_write_config_byte(dev, E752X_HI_FERR, info->hi_ferr); + if (info->nsi_ferr & NSI_ERR_MASK) + pci_write_config_dword(dev, I3100_NSI_FERR, + info->nsi_ferr); + if (info->sysbus_ferr) pci_write_config_word(dev, E752X_SYSBUS_FERR, info->sysbus_ferr); @@ -692,7 +809,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); if (info->nerr_global) { - pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_read_config_dword(dev, I3100_NSI_NERR, + &info->nsi_nerr); + info->hi_nerr = 0; + } else { + pci_read_config_byte(dev, E752X_HI_NERR, + &info->hi_nerr); + info->nsi_nerr = 0; + } pci_read_config_word(dev, E752X_SYSBUS_NERR, &info->sysbus_nerr); pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); @@ -706,6 +831,10 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_write_config_byte(dev, E752X_HI_NERR, info->hi_nerr); + if (info->nsi_nerr & NSI_ERR_MASK) + pci_write_config_dword(dev, I3100_NSI_NERR, + info->nsi_nerr); + if (info->sysbus_nerr) pci_write_config_word(dev, E752X_SYSBUS_NERR, info->sysbus_nerr); @@ -750,6 +879,7 @@ static int e752x_process_error_info(struct mem_ctl_info *mci, global_error(0, stat32, &error_found, handle_errors); e752x_check_hub_interface(info, &error_found, handle_errors); + e752x_check_ns_interface(info, &error_found, handle_errors); e752x_check_sysbus(info, &error_found, handle_errors); e752x_check_membuf(info, &error_found, handle_errors); e752x_check_dram(mci, info, &error_found, handle_errors); @@ -920,15 +1050,53 @@ fail: return 1; } +/* Setup system bus parity mask register. + * Sysbus parity supported on: + * e7320/e7520/e7525 + Xeon + * i3100 + Xeon/Celeron + * Sysbus parity not supported on: + * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo + */ +static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) +{ + char *cpu_id = cpu_data(0).x86_model_id; + struct pci_dev *dev = pvt->dev_d0f1; + int enable = 1; + + /* Allow module paramter override, else see if CPU supports parity */ + if (sysbus_parity != -1) { + enable = sysbus_parity; + } else if (cpu_id[0] && + ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) || + (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) || + (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) { + e752x_printk(KERN_INFO, "System Bus Parity not " + "supported by CPU, disabling\n"); + enable = 0; + } + + if (enable) + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000); + else + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309); +} + static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) { struct pci_dev *dev; dev = pvt->dev_d0f1; /* Turn off error disable & SMI in case the BIOS turned it on */ - pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); - pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); - pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_write_config_dword(dev, I3100_NSI_EMASK, 0); + pci_write_config_dword(dev, I3100_NSI_SMICMD, 0); + } else { + pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); + } + + e752x_init_sysbus_parity_mask(pvt); + pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); @@ -949,16 +1117,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); debugf0("Starting Probe1\n"); - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - /* check to see if device 0 function 1 is enabled; if it isn't, we * assume the BIOS has reserved it for a reason and is expecting * exclusive access, we take care not to violate that assumption and @@ -985,8 +1143,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf3("%s(): init mci\n", __func__); mci->mtype_cap = MEM_FLAG_RDDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | - EDAC_FLAG_S4ECD4ED; + /* 3100 IMCH supports SECDEC only */ + mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED : + (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED); /* FIXME - what if different memory types are in different csrows? */ mci->mod_name = EDAC_MOD_STR; mci->mod_ver = E752X_REVISION; @@ -1018,7 +1177,10 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) e752x_init_csrows(mci, pdev, ddrcsr); e752x_init_mem_map_table(pdev, pvt); - mci->edac_cap |= EDAC_FLAG_NONE; + if (dev_idx == I3100) + mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */ + else + mci->edac_cap |= EDAC_FLAG_NONE; debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); /* load the top of low memory, remap base, and remap limit vars */ @@ -1110,6 +1272,9 @@ static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7320}, { + PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + I3100}, + { 0, } /* 0 terminated list. */ }; @@ -1128,6 +1293,10 @@ static int __init e752x_init(void) int pci_rc; debugf3("%s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&e752x_driver); return (pci_rc < 0) ? pci_rc : 0; } @@ -1143,10 +1312,15 @@ module_exit(e752x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); -MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); +MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); module_param(force_function_unhide, int, 0444); MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); + module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); + +module_param(sysbus_parity, int, 0444); +MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking," + " 1=enable system bus parity checking, default=auto-detect"); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 96ecc4926641..c7d11cc4e21a 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -414,16 +414,6 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - pci_read_config_dword(pdev, E7XXX_DRC, &drc); drc_chan = dual_channel_active(drc, dev_idx); @@ -565,6 +555,9 @@ static struct pci_driver e7xxx_driver = { static int __init e7xxx_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&e7xxx_driver); } diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index b9552bc03dea..63372fa7ecfe 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -36,7 +36,7 @@ * is protected by the 'device_ctls_mutex' lock */ static DEFINE_MUTEX(device_ctls_mutex); -static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list); +static LIST_HEAD(edac_device_list); #ifdef CONFIG_EDAC_DEBUG static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) @@ -375,37 +375,6 @@ static void del_edac_device_from_global_list(struct edac_device_ctl_info wait_for_completion(&edac_device->removal_complete); } -/** - * edac_device_find - * Search for a edac_device_ctl_info structure whose index is 'idx'. - * - * If found, return a pointer to the structure. - * Else return NULL. - * - * Caller must hold device_ctls_mutex. - */ -struct edac_device_ctl_info *edac_device_find(int idx) -{ - struct list_head *item; - struct edac_device_ctl_info *edac_dev; - - /* Iterate over list, looking for exact match of ID */ - list_for_each(item, &edac_device_list) { - edac_dev = list_entry(item, struct edac_device_ctl_info, link); - - if (edac_dev->dev_idx >= idx) { - if (edac_dev->dev_idx == idx) - return edac_dev; - - /* not on list, so terminate early */ - break; - } - } - - return NULL; -} -EXPORT_SYMBOL_GPL(edac_device_find); - /* * edac_device_workq_function * performs the operation scheduled by a workq request diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 063a1bffe38b..a4cf1645f588 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -36,7 +36,7 @@ /* lock to memory controller's control array */ static DEFINE_MUTEX(mem_ctls_mutex); -static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); +static LIST_HEAD(mc_devices); #ifdef CONFIG_EDAC_DEBUG @@ -886,24 +886,3 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, mci->csrows[csrow].channels[channel].ce_count++; } EXPORT_SYMBOL(edac_mc_handle_fbd_ce); - -/* - * Iterate over all MC instances and check for ECC, et al, errors - */ -void edac_check_mc_devices(void) -{ - struct list_head *item; - struct mem_ctl_info *mci; - - debugf3("%s()\n", __func__); - mutex_lock(&mem_ctls_mutex); - - list_for_each(item, &mc_devices) { - mci = list_entry(item, struct mem_ctl_info, link); - - if (mci->edac_check != NULL) - mci->edac_check(mci); - } - - mutex_unlock(&mem_ctls_mutex); -} diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index cbc419c8ebc1..233d4798c3aa 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -27,7 +27,6 @@ extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci); extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci); extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci); extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci); -extern void edac_check_mc_devices(void); extern int edac_get_log_ue(void); extern int edac_get_log_ce(void); extern int edac_get_panic_on_ue(void); diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 32be43576a8e..9b24340b52e1 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -29,7 +29,7 @@ #include "edac_module.h" static DEFINE_MUTEX(edac_pci_ctls_mutex); -static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list); +static LIST_HEAD(edac_pci_list); /* * edac_pci_alloc_ctl_info @@ -189,6 +189,9 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) wait_for_completion(&pci->complete); } +#if 0 +/* Older code, but might use in the future */ + /* * edac_pci_find() * Search for an edac_pci_ctl_info structure whose index is 'idx' @@ -219,6 +222,7 @@ struct edac_pci_ctl_info *edac_pci_find(int idx) return NULL; } EXPORT_SYMBOL_GPL(edac_pci_find); +#endif /* * edac_pci_workq_function() @@ -422,7 +426,7 @@ EXPORT_SYMBOL_GPL(edac_pci_del_device); * * a Generic parity check API */ -void edac_pci_generic_check(struct edac_pci_ctl_info *pci) +static void edac_pci_generic_check(struct edac_pci_ctl_info *pci) { debugf4("%s()\n", __func__); edac_pci_do_parity_check(); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 71c3195d3704..2c1fa1bb6df2 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -37,17 +37,17 @@ int edac_pci_get_check_errors(void) return check_pci_errors; } -int edac_pci_get_log_pe(void) +static int edac_pci_get_log_pe(void) { return edac_pci_log_pe; } -int edac_pci_get_log_npe(void) +static int edac_pci_get_log_npe(void) { return edac_pci_log_npe; } -int edac_pci_get_panic_on_pe(void) +static int edac_pci_get_panic_on_pe(void) { return edac_pci_panic_on_pe; } @@ -197,7 +197,8 @@ error_out: * * unregister the kobj for the EDAC PCI instance */ -void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci) +static void edac_pci_unregister_sysfs_instance_kobj( + struct edac_pci_ctl_info *pci) { debugf0("%s()\n", __func__); @@ -337,7 +338,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = { * setup the sysfs for EDAC PCI attributes * assumes edac_class has already been initialized */ -int edac_pci_main_kobj_setup(void) +static int edac_pci_main_kobj_setup(void) { int err; struct sysdev_class *edac_class; diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 5d4292811c14..6c9a0f2a593c 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -326,15 +326,6 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) return -ENODEV; } - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */ c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */ c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */ @@ -503,6 +494,10 @@ static int __init i3000_init(void) int pci_rc; debugf3("MC: %s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i3000_driver); if (pci_rc < 0) goto fail0; diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 5a852017c17a..4a16b5b61cfb 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1286,16 +1286,6 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx) if (PCI_FUNC(pdev->devfn) != 0) return -ENODEV; - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - /* Ask the devices for the number of CSROWS and CHANNELS so * that we can calculate the memory resources, etc * @@ -1478,6 +1468,9 @@ static int __init i5000_init(void) debugf2("MC: " __FILE__ ": %s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i5000_driver); return (pci_rc < 0) ? pci_rc : 0; @@ -1501,5 +1494,6 @@ MODULE_AUTHOR ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>"); MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - " I5000_REVISION); + module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 83bfe37c4bbb..c5305e3ee434 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -29,6 +29,7 @@ #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82443_REVISION "0.1" @@ -386,6 +387,9 @@ static struct pci_driver i82443bxgx_edacmc_driver = { static int __init i82443bxgx_edacmc_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&i82443bxgx_edacmc_driver); } @@ -400,3 +404,6 @@ module_exit(i82443bxgx_edacmc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD"); MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index f5ecd2c4d813..c0088ba9672b 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -14,6 +14,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82860_REVISION " Ver: 2.0.2 " __DATE__ @@ -294,6 +295,9 @@ static int __init i82860_init(void) debugf3("%s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) goto fail0; @@ -345,3 +349,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " "Ben Woodard <woodard@redhat.com>"); MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 031abadc439a..e43bdc43a1bf 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82875P_REVISION " Ver: 2.0.2 " __DATE__ @@ -393,6 +394,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) struct i82875p_error_info discard; debugf0("%s()\n", __func__); + ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window)) @@ -532,6 +534,10 @@ static int __init i82875p_init(void) int pci_rc; debugf3("%s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i82875p_driver); if (pci_rc < 0) @@ -586,3 +592,6 @@ module_exit(i82875p_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 0ee888456932..2eed3ea2cf62 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -14,7 +14,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> - +#include <linux/edac.h> #include "edac_core.h" #define I82975X_REVISION " Ver: 1.0.0 " __DATE__ @@ -611,6 +611,9 @@ static int __init i82975x_init(void) debugf3("%s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i82975x_driver); if (pci_rc < 0) goto fail0; @@ -664,3 +667,6 @@ module_exit(i82975x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>"); MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 90320917be28..8e6b91bd2e99 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c @@ -26,6 +26,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define MODULE_NAME "pasemi_edac" @@ -284,6 +285,9 @@ static struct pci_driver pasemi_edac_driver = { static int __init pasemi_edac_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&pasemi_edac_driver); } @@ -298,3 +302,6 @@ module_exit(pasemi_edac_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller"); +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); + diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index e25f712f2dc3..9900675e9598 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -20,6 +20,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define R82600_REVISION " Ver: 2.0.2 " __DATE__ @@ -393,6 +394,9 @@ static struct pci_driver r82600_driver = { static int __init r82600_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&r82600_driver); } @@ -412,3 +416,6 @@ MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644); MODULE_PARM_DESC(disable_hardware_scrub, "If set, disable the chipset's automatic scrub for CEs"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index dda82f37cab3..b2458bb8e9ca 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -784,7 +784,7 @@ static void sbp2_release_target(struct kref *kref) kfree(lu); } scsi_remove_host(shost); - fw_notify("released %s\n", tgt->bus_id); + fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); fw_unit_put(tgt->unit); scsi_host_put(shost); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 40ffd767647d..dc2cec6127d1 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -17,6 +17,15 @@ config EDD obscure configurations. Most disk controller BIOS vendors do not yet implement this feature. +config EDD_OFF + bool "Sets default behavior for EDD detection to off" + depends on EDD + default n + help + Say Y if you want EDD disabled by default, even though it is compiled into the + kernel. Say N if you want EDD enabled by default. EDD can be dynamically set + using the kernel parameter 'edd={on|skipmbr|off}'. + config EFI_VARS tristate "EFI Variable Support via sysfs" depends on EFI diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index f235940719e7..25918f7dfd0f 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -63,7 +63,7 @@ static void smi_data_buf_free(void) return; dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", - __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size); + __func__, smi_data_buf_phys_addr, smi_data_buf_size); dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf, smi_data_buf_handle); @@ -92,7 +92,7 @@ static int smi_data_buf_realloc(unsigned long size) if (!buf) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to allocate memory size %lu\n", - __FUNCTION__, size); + __func__, size); return -ENOMEM; } /* memory zeroed by dma_alloc_coherent */ @@ -110,7 +110,7 @@ static int smi_data_buf_realloc(unsigned long size) smi_data_buf_size = size; dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", - __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size); + __func__, smi_data_buf_phys_addr, smi_data_buf_size); return 0; } @@ -258,7 +258,7 @@ static int smi_request(struct smi_cmd *smi_cmd) if (smi_cmd->magic != SMI_CMD_MAGIC) { dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n", - __FUNCTION__); + __func__); return -EBADR; } @@ -267,7 +267,7 @@ static int smi_request(struct smi_cmd *smi_cmd) set_cpus_allowed_ptr(current, &cpumask_of_cpu(0)); if (smp_processor_id() != 0) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", - __FUNCTION__); + __func__); ret = -EBUSY; goto out; } @@ -428,7 +428,7 @@ static int host_control_smi(void) default: dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n", - __FUNCTION__, host_control_smi_type); + __func__, host_control_smi_type); return -ENOSYS; } @@ -456,13 +456,13 @@ static void dcdbas_host_control(void) host_control_action = HC_ACTION_NONE; if (!smi_data_buf) { - dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__); + dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__); return; } if (smi_data_buf_size < sizeof(struct apm_cmd)) { dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n", - __FUNCTION__); + __func__); return; } diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 477a3d0e3caf..6a8b1e037e07 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -123,7 +123,7 @@ static int create_packet(void *data, size_t length) if (!newpacket) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "packet\n", __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_noalloc; @@ -152,7 +152,7 @@ static int create_packet(void *data, size_t length) printk(KERN_WARNING "dell_rbu:%s: failed to allocate " "invalid_addr_packet_array \n", - __FUNCTION__); + __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_alloc_packet; @@ -164,7 +164,7 @@ static int create_packet(void *data, size_t length) if (!packet_data_temp_buf) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "packet\n", __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_alloc_packet_array; @@ -416,7 +416,7 @@ static int img_update_realloc(unsigned long size) */ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { printk(KERN_ERR "dell_rbu:%s: corruption " - "check failed\n", __FUNCTION__); + "check failed\n", __func__); return -EINVAL; } /* @@ -642,7 +642,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, if (req_firm_rc) { printk(KERN_ERR "dell_rbu:%s request_firmware_nowait" - " failed %d\n", __FUNCTION__, rc); + " failed %d\n", __func__, rc); rc = -EIO; } else rbu_data.entry_created = 1; @@ -718,7 +718,7 @@ static int __init dcdrbu_init(void) if (IS_ERR(rbu_device)) { printk(KERN_ERR "dell_rbu:%s:platform_device_register_simple " - "failed\n", __FUNCTION__); + "failed\n", __func__); return PTR_ERR(rbu_device); } diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index d0e5fa4ea51b..11f17440fea6 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -58,7 +58,7 @@ void __init reserve_ibft_region(void) unsigned int len = 0; void *virt; - ibft_addr = 0; + ibft_addr = NULL; for (pos = IBFT_START; pos < IBFT_END; pos += 16) { /* The table can't be inside the VGA BIOS reserved space, diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d8db2f8ee411..7f138c6195ff 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -43,6 +43,7 @@ struct gpio_desc { /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 +#define FLAG_RESERVED 2 #ifdef CONFIG_DEBUG_FS const char *label; @@ -68,6 +69,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc)); desc_set_label(desc, "[auto]"); + if (!try_module_get(desc->chip->owner)) + pr_err("GPIO-%d: module can't be gotten \n", + (int)(desc - gpio_desc)); } } @@ -77,6 +81,76 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) return gpio_desc[gpio].chip; } +/* dynamic allocation of GPIOs, e.g. on a hotplugged device */ +static int gpiochip_find_base(int ngpio) +{ + int i; + int spare = 0; + int base = -ENOSPC; + + for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { + struct gpio_desc *desc = &gpio_desc[i]; + struct gpio_chip *chip = desc->chip; + + if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { + spare++; + if (spare == ngpio) { + base = i; + break; + } + } else { + spare = 0; + if (chip) + i -= chip->ngpio - 1; + } + } + + if (gpio_is_valid(base)) + pr_debug("%s: found new base at %d\n", __func__, base); + return base; +} + +/** + * gpiochip_reserve() - reserve range of gpios to use with platform code only + * @start: starting gpio number + * @ngpio: number of gpios to reserve + * Context: platform init, potentially before irqs or kmalloc will work + * + * Returns a negative errno if any gpio within the range is already reserved + * or registered, else returns zero as a success code. Use this function + * to mark a range of gpios as unavailable for dynamic gpio number allocation, + * for example because its driver support is not yet loaded. + */ +int __init gpiochip_reserve(int start, int ngpio) +{ + int ret = 0; + unsigned long flags; + int i; + + if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio)) + return -EINVAL; + + spin_lock_irqsave(&gpio_lock, flags); + + for (i = start; i < start + ngpio; i++) { + struct gpio_desc *desc = &gpio_desc[i]; + + if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) { + ret = -EBUSY; + goto err; + } + + set_bit(FLAG_RESERVED, &desc->flags); + } + + pr_debug("%s: reserved gpios from %d to %d\n", + __func__, start, start + ngpio - 1); +err: + spin_unlock_irqrestore(&gpio_lock, flags); + + return ret; +} + /** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized @@ -85,38 +159,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) * Returns a negative errno if the chip can't be registered, such as * because the chip->base is invalid or already associated with a * different chip. Otherwise it returns zero as a success code. + * + * If chip->base is negative, this requests dynamic assignment of + * a range of valid GPIOs. */ int gpiochip_add(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; + int base = chip->base; - /* NOTE chip->base negative is reserved to mean a request for - * dynamic allocation. We don't currently support that. - */ - - if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) { + if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio)) + && base >= 0) { status = -EINVAL; goto fail; } spin_lock_irqsave(&gpio_lock, flags); + if (base < 0) { + base = gpiochip_find_base(chip->ngpio); + if (base < 0) { + status = base; + goto fail_unlock; + } + chip->base = base; + } + /* these GPIO numbers must not be managed by another gpio_chip */ - for (id = chip->base; id < chip->base + chip->ngpio; id++) { + for (id = base; id < base + chip->ngpio; id++) { if (gpio_desc[id].chip != NULL) { status = -EBUSY; break; } } if (status == 0) { - for (id = chip->base; id < chip->base + chip->ngpio; id++) { + for (id = base; id < base + chip->ngpio; id++) { gpio_desc[id].chip = chip; gpio_desc[id].flags = 0; } } +fail_unlock: spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ @@ -171,12 +256,15 @@ int gpio_request(unsigned gpio, const char *label) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto done; desc = &gpio_desc[gpio]; if (desc->chip == NULL) goto done; + if (!try_module_get(desc->chip->owner)) + goto done; + /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled. */ @@ -184,8 +272,10 @@ int gpio_request(unsigned gpio, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { desc_set_label(desc, label ? : "?"); status = 0; - } else + } else { status = -EBUSY; + module_put(desc->chip->owner); + } done: if (status) @@ -201,7 +291,7 @@ void gpio_free(unsigned gpio) unsigned long flags; struct gpio_desc *desc; - if (gpio >= ARCH_NR_GPIOS) { + if (!gpio_is_valid(gpio)) { WARN_ON(extra_checks); return; } @@ -209,9 +299,10 @@ void gpio_free(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) + if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) { desc_set_label(desc, NULL); - else + module_put(desc->chip->owner); + } else WARN_ON(extra_checks); spin_unlock_irqrestore(&gpio_lock, flags); @@ -236,7 +327,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { unsigned gpio = chip->base + offset; - if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip) + if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) return NULL; if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) return NULL; @@ -267,7 +358,7 @@ int gpio_direction_input(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) @@ -291,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); @@ -305,7 +396,7 @@ int gpio_direction_output(unsigned gpio, int value) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->direction_output) @@ -329,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); @@ -522,7 +613,7 @@ static int gpiolib_show(struct seq_file *s, void *unused) /* REVISIT this isn't locked against gpio_chip removal ... */ - for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { + for (gpio = 0; gpio_is_valid(gpio); gpio++) { if (chip == gpio_desc[gpio].chip) continue; chip = gpio_desc[gpio].chip; diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c index bb60e8c1a1f0..7fb5b9d009d4 100644 --- a/drivers/gpio/mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_device *spi) mcp->chip.base = pdata->base; mcp->chip.ngpio = 8; mcp->chip.can_sleep = 1; + mcp->chip.owner = THIS_MODULE; spi_set_drvdata(spi, mcp); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 6e72fd31184d..93f916720b13 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -23,21 +23,19 @@ #define PCA953X_INVERT 2 #define PCA953X_DIRECTION 3 -/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */ -struct pca953x_desc { - char name[I2C_NAME_SIZE]; - unsigned long driver_data; -}; - -static const struct pca953x_desc pca953x_descs[] = { +static const struct i2c_device_id pca953x_id[] = { { "pca9534", 8, }, { "pca9535", 16, }, { "pca9536", 4, }, { "pca9537", 4, }, { "pca9538", 8, }, { "pca9539", 16, }, + { "pca9555", 16, }, + { "pca9557", 8, }, /* REVISIT several pca955x parts should work here too */ + { } }; +MODULE_DEVICE_TABLE(i2c, pca953x_id); struct pca953x_chip { unsigned gpio_start; @@ -189,28 +187,20 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->base = chip->gpio_start; gc->ngpio = gpios; gc->label = chip->client->name; + gc->owner = THIS_MODULE; } -static int __devinit pca953x_probe(struct i2c_client *client) +static int __devinit pca953x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; - int ret, i; - const struct pca953x_desc *id = NULL; + int ret; pdata = client->dev.platform_data; if (pdata == NULL) return -ENODEV; - /* this loop vanishes when we get i2c_device_id */ - for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++) - if (!strcmp(pca953x_descs[i].name, client->name)) { - id = pca953x_descs + i; - break; - } - if (!id) - return -ENODEV; - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -290,6 +280,7 @@ static struct i2c_driver pca953x_driver = { }, .probe = pca953x_probe, .remove = pca953x_remove, + .id_table = pca953x_id, }; static int __init pca953x_init(void) diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c index c6b3b5378384..aa6cc8b2a2bc 100644 --- a/drivers/gpio/pcf857x.c +++ b/drivers/gpio/pcf857x.c @@ -26,6 +26,21 @@ #include <asm/gpio.h> +static const struct i2c_device_id pcf857x_id[] = { + { "pcf8574", 8 }, + { "pca8574", 8 }, + { "pca9670", 8 }, + { "pca9672", 8 }, + { "pca9674", 8 }, + { "pcf8575", 16 }, + { "pca8575", 16 }, + { "pca9671", 16 }, + { "pca9673", 16 }, + { "pca9675", 16 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf857x_id); + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -142,7 +157,8 @@ static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) /*-------------------------------------------------------------------------*/ -static int pcf857x_probe(struct i2c_client *client) +static int pcf857x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf857x_platform_data *pdata; struct pcf857x *gpio; @@ -159,6 +175,7 @@ static int pcf857x_probe(struct i2c_client *client) gpio->chip.base = pdata->gpio_base; gpio->chip.can_sleep = 1; + gpio->chip.owner = THIS_MODULE; /* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution @@ -171,13 +188,8 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between *4 and *4a parts. */ - if (strcmp(client->name, "pcf8574") == 0 - || strcmp(client->name, "pca8574") == 0 - || strcmp(client->name, "pca9670") == 0 - || strcmp(client->name, "pca9672") == 0 - || strcmp(client->name, "pca9674") == 0 - ) { - gpio->chip.ngpio = 8; + gpio->chip.ngpio = id->driver_data; + if (gpio->chip.ngpio == 8) { gpio->chip.direction_input = pcf857x_input8; gpio->chip.get = pcf857x_get8; gpio->chip.direction_output = pcf857x_output8; @@ -197,13 +209,7 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between '75 and '75c parts. */ - } else if (strcmp(client->name, "pcf8575") == 0 - || strcmp(client->name, "pca8575") == 0 - || strcmp(client->name, "pca9671") == 0 - || strcmp(client->name, "pca9673") == 0 - || strcmp(client->name, "pca9675") == 0 - ) { - gpio->chip.ngpio = 16; + } else if (gpio->chip.ngpio == 16) { gpio->chip.direction_input = pcf857x_input16; gpio->chip.get = pcf857x_get16; gpio->chip.direction_output = pcf857x_output16; @@ -312,6 +318,7 @@ static struct i2c_driver pcf857x_driver = { }, .probe = pcf857x_probe, .remove = pcf857x_remove, + .id_table = pcf857x_id, }; static int __init pcf857x_init(void) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e03c67dd3e63..f43d6d3cf2fa 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -606,7 +606,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) case 2: if ((end - start) < 2) return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); + item->data.u16 = get_unaligned_le16(start); start = (__u8 *)((__le16 *)start + 1); return start; @@ -614,7 +614,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) item->size++; if ((end - start) < 4) return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); + item->data.u32 = get_unaligned_le32(start); start = (__u8 *)((__le32 *)start + 1); return start; } @@ -765,7 +765,7 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) report += offset >> 3; /* adjust byte index */ offset &= 7; /* now only need bit offset into one byte */ - x = le64_to_cpu(get_unaligned((__le64 *) report)); + x = get_unaligned_le64(report); x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ return (u32) x; } diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e0d805f1b2bf..01427c51c7cc 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -654,7 +654,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), + ((HID_OUTPUT_REPORT + 1) << 8) | *buf, interface->desc.bInterfaceNumber, buf + 1, count - 1, USB_CTRL_SET_TIMEOUT); diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index ed71a8bc70dc..5c8b6e0ff47c 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/hwmon/adt7473.c b/drivers/hwmon/adt7473.c index 9587869bdba0..c1009d6f9796 100644 --- a/drivers/hwmon/adt7473.c +++ b/drivers/hwmon/adt7473.c @@ -422,18 +422,14 @@ static ssize_t show_volt(struct device *dev, struct device_attribute *devattr, * number in the range -128 to 127, or as an unsigned number that must * be offset by 64. */ -static int decode_temp(struct adt7473_data *data, u8 raw) +static int decode_temp(u8 twos_complement, u8 raw) { - if (data->temp_twos_complement) - return (s8)raw; - return raw - 64; + return twos_complement ? (s8)raw : raw - 64; } -static u8 encode_temp(struct adt7473_data *data, int cooked) +static u8 encode_temp(u8 twos_complement, int cooked) { - if (data->temp_twos_complement) - return (cooked & 0xFF); - return cooked + 64; + return twos_complement ? cooked & 0xFF : cooked + 64; } static ssize_t show_temp_min(struct device *dev, @@ -442,8 +438,9 @@ static ssize_t show_temp_min(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adt7473_data *data = adt7473_update_device(dev); - return sprintf(buf, "%d\n", - 1000 * decode_temp(data, data->temp_min[attr->index])); + return sprintf(buf, "%d\n", 1000 * decode_temp( + data->temp_twos_complement, + data->temp_min[attr->index])); } static ssize_t set_temp_min(struct device *dev, @@ -455,7 +452,7 @@ static ssize_t set_temp_min(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adt7473_data *data = i2c_get_clientdata(client); int temp = simple_strtol(buf, NULL, 10) / 1000; - temp = encode_temp(data, temp); + temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); data->temp_min[attr->index] = temp; @@ -472,8 +469,9 @@ static ssize_t show_temp_max(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adt7473_data *data = adt7473_update_device(dev); - return sprintf(buf, "%d\n", - 1000 * decode_temp(data, data->temp_max[attr->index])); + return sprintf(buf, "%d\n", 1000 * decode_temp( + data->temp_twos_complement, + data->temp_max[attr->index])); } static ssize_t set_temp_max(struct device *dev, @@ -485,7 +483,7 @@ static ssize_t set_temp_max(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adt7473_data *data = i2c_get_clientdata(client); int temp = simple_strtol(buf, NULL, 10) / 1000; - temp = encode_temp(data, temp); + temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); data->temp_max[attr->index] = temp; @@ -501,8 +499,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adt7473_data *data = adt7473_update_device(dev); - return sprintf(buf, "%d\n", - 1000 * decode_temp(data, data->temp[attr->index])); + return sprintf(buf, "%d\n", 1000 * decode_temp( + data->temp_twos_complement, + data->temp[attr->index])); } static ssize_t show_fan_min(struct device *dev, @@ -671,8 +670,9 @@ static ssize_t show_temp_tmax(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adt7473_data *data = adt7473_update_device(dev); - return sprintf(buf, "%d\n", - 1000 * decode_temp(data, data->temp_tmax[attr->index])); + return sprintf(buf, "%d\n", 1000 * decode_temp( + data->temp_twos_complement, + data->temp_tmax[attr->index])); } static ssize_t set_temp_tmax(struct device *dev, @@ -684,7 +684,7 @@ static ssize_t set_temp_tmax(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adt7473_data *data = i2c_get_clientdata(client); int temp = simple_strtol(buf, NULL, 10) / 1000; - temp = encode_temp(data, temp); + temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); data->temp_tmax[attr->index] = temp; @@ -701,8 +701,9 @@ static ssize_t show_temp_tmin(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adt7473_data *data = adt7473_update_device(dev); - return sprintf(buf, "%d\n", - 1000 * decode_temp(data, data->temp_tmin[attr->index])); + return sprintf(buf, "%d\n", 1000 * decode_temp( + data->temp_twos_complement, + data->temp_tmin[attr->index])); } static ssize_t set_temp_tmin(struct device *dev, @@ -714,7 +715,7 @@ static ssize_t set_temp_tmin(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adt7473_data *data = i2c_get_clientdata(client); int temp = simple_strtol(buf, NULL, 10) / 1000; - temp = encode_temp(data, temp); + temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); data->temp_tmin[attr->index] = temp; diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 84712a22acea..fe2eea4d799b 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -953,12 +953,8 @@ static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) static void asb100_init_client(struct i2c_client *client) { struct asb100_data *data = i2c_get_clientdata(client); - int vid = 0; - vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; - vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; data->vrm = vid_which_vrm(); - vid = vid_from_reg(vid, data->vrm); /* Start monitoring */ asb100_write_value(client, ASB100_REG_CONFIG, diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 1464338e4e11..dc1f30e432ea 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -117,7 +117,8 @@ struct f75375_data { static int f75375_attach_adapter(struct i2c_adapter *adapter); static int f75375_detect(struct i2c_adapter *adapter, int address, int kind); static int f75375_detach_client(struct i2c_client *client); -static int f75375_probe(struct i2c_client *client); +static int f75375_probe(struct i2c_client *client, + const struct i2c_device_id *id); static int f75375_remove(struct i2c_client *client); static struct i2c_driver f75375_legacy_driver = { @@ -128,12 +129,20 @@ static struct i2c_driver f75375_legacy_driver = { .detach_client = f75375_detach_client, }; +static const struct i2c_device_id f75375_id[] = { + { "f75373", f75373 }, + { "f75375", f75375 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, f75375_id); + static struct i2c_driver f75375_driver = { .driver = { .name = "f75375", }, .probe = f75375_probe, .remove = f75375_remove, + .id_table = f75375_id, }; static inline int f75375_read8(struct i2c_client *client, u8 reg) @@ -628,7 +637,8 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, } -static int f75375_probe(struct i2c_client *client) +static int f75375_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct f75375_data *data = i2c_get_clientdata(client); struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data; @@ -643,15 +653,7 @@ static int f75375_probe(struct i2c_client *client) i2c_set_clientdata(client, data); data->client = client; mutex_init(&data->update_lock); - - if (strcmp(client->name, "f75375") == 0) - data->kind = f75375; - else if (strcmp(client->name, "f75373") == 0) - data->kind = f75373; - else { - dev_err(&client->dev, "Unsupported device: %s\n", client->name); - return -ENODEV; - } + data->kind = id->driver_data; if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group))) goto exit_free; @@ -712,6 +714,7 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) u8 version = 0; int err = 0; const char *name = ""; + struct i2c_device_id id; if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) { err = -ENOMEM; @@ -748,7 +751,9 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = i2c_attach_client(client))) goto exit_free; - if ((err = f75375_probe(client)) < 0) + strlcpy(id.name, name, I2C_NAME_SIZE); + id.driver_data = kind; + if ((err = f75375_probe(client, &id)) < 0) goto exit_detach; return 0; diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 115f4090b98e..fa7696905154 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -248,7 +248,7 @@ static int lm75_detach_client(struct i2c_client *client) /* All registers are word-sized, except for the configuration register. LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ + the SMBus standard. */ static int lm75_read_value(struct i2c_client *client, u8 reg) { if (reg == LM75_REG_CONF) @@ -257,9 +257,6 @@ static int lm75_read_value(struct i2c_client *client, u8 reg) return swab16(i2c_smbus_read_word_data(client, reg)); } -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) { if (reg == LM75_REG_CONF) diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index f61d8f4185b2..eb03544c731c 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -335,11 +335,23 @@ exit: static int __init smsc47b397_find(unsigned short *addr) { u8 id, rev; + char *name; superio_enter(); id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); - if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) { + switch(id) { + case 0x81: + name = "SCH5307-NS"; + break; + case 0x6f: + name = "LPC47B397-NC"; + break; + case 0x85: + case 0x8c: + name = "SCH5317"; + break; + default: superio_exit(); return -ENODEV; } @@ -352,8 +364,7 @@ static int __init smsc47b397_find(unsigned short *addr) printk(KERN_INFO DRVNAME ": found SMSC %s " "(base address 0x%04x, revision %u)\n", - id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" : - "LPC47B397-NC", *addr, rev); + name, *addr, rev); superio_exit(); return 0; diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index ee35af93b574..ed3c019b78c7 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1024,10 +1024,9 @@ static struct sensor_device_attribute_2 w83793_vid[] = { SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0), SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1), }; +static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm); static struct sensor_device_attribute_2 sda_single_files[] = { - SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm, - NOT_USED, NOT_USED), SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, store_chassis_clear, ALARM_STATUS, 30), SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, @@ -1080,6 +1079,7 @@ static int w83793_detach_client(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) device_remove_file(dev, &w83793_vid[i].dev_attr); + device_remove_file(dev, &dev_attr_vrm); for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++) device_remove_file(dev, &w83793_left_fan[i].dev_attr); @@ -1282,7 +1282,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the chip */ w83793_init_client(client); - data->vrm = vid_which_vrm(); /* Only fan 1-5 has their own input pins, Pwm 1-3 has their own pins @@ -1293,7 +1292,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) val = w83793_read_value(client, W83793_REG_FANIN_CTRL); /* check the function of pins 49-56 */ - if (!(tmp & 0x80)) { + if (tmp & 0x80) { + data->has_vid |= 0x2; /* has VIDB */ + } else { data->has_pwm |= 0x18; /* pwm 4,5 */ if (val & 0x01) { /* fan 6 */ data->has_fan |= 0x20; @@ -1309,13 +1310,15 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) } } + /* check the function of pins 37-40 */ + if (!(tmp & 0x29)) + data->has_vid |= 0x1; /* has VIDA */ if (0x08 == (tmp & 0x0c)) { if (val & 0x08) /* fan 9 */ data->has_fan |= 0x100; if (val & 0x10) /* fan 10 */ data->has_fan |= 0x200; } - if (0x20 == (tmp & 0x30)) { if (val & 0x20) /* fan 11 */ data->has_fan |= 0x400; @@ -1359,13 +1362,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) if (tmp & 0x02) data->has_temp |= 0x20; - /* Detect the VID usage and ignore unused input */ - tmp = w83793_read_value(client, W83793_REG_MFC); - if (!(tmp & 0x29)) - data->has_vid |= 0x1; /* has VIDA */ - if (tmp & 0x80) - data->has_vid |= 0x2; /* has VIDB */ - /* Register sysfs hooks */ for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) { err = device_create_file(dev, @@ -1381,6 +1377,12 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) if (err) goto exit_remove; } + if (data->has_vid) { + data->vrm = vid_which_vrm(); + err = device_create_file(dev, &dev_attr_vrm); + if (err) + goto exit_remove; + } for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { err = device_create_file(dev, &sda_single_files[i].dev_attr); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 77f2d482888b..52e268e25dab 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -301,8 +301,8 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) msleep(i); } - dev_err(&client->dev, "Couldn't read value from register 0x%02x. " - "Please report.\n", reg); + dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n", + reg); return defval; } diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index e5e96c817566..c38a0a112208 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -1,7 +1,7 @@ /* * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard * - * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2004, 2008 Jean Delvare <khali@linux-fr.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 @@ -231,7 +231,8 @@ ERROR2: kfree(s4882_adapter); s4882_adapter = NULL; ERROR1: - i2c_del_adapter(&amd756_smbus); + /* Restore physical bus */ + i2c_add_adapter(&amd756_smbus); ERROR0: return error; } diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 9bbe96cef719..fdc9ad805e35 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -38,7 +38,6 @@ #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> -#include <linux/apm_bios.h> #include <linux/dmi.h> #include <asm/io.h> @@ -223,7 +222,7 @@ static int piix4_transaction(void) dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&piix4_adapter.dev, "Successfull!\n"); + dev_dbg(&piix4_adapter.dev, "Successful!\n"); } } @@ -343,12 +342,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, switch (size) { - case PIIX4_BYTE: /* Where is the result put? I assume here it is in - SMBHSTDAT0 but it might just as well be in the - SMBHSTCMD. No clue in the docs */ - - data->byte = inb_p(SMBHSTDAT0); - break; + case PIIX4_BYTE: case PIIX4_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 283769cecee2..9ca8f9155f95 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -238,7 +238,7 @@ static int sis5595_transaction(struct i2c_adapter *adap) dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&adap->dev, "Successfull!\n"); + dev_dbg(&adap->dev, "Successful!\n"); } } @@ -316,14 +316,8 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, } size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA; break; -/* - case I2C_SMBUS_BLOCK_DATA: - printk(KERN_WARNING "sis5595.o: Block data not yet implemented!\n"); - return -1; - break; -*/ default: - printk(KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size); + dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -1; } @@ -338,9 +332,7 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, switch (size) { - case SIS5595_BYTE: /* Where is the result put? I assume here it is in - SMB_DATA but it might just as well be in the - SMB_CMD. No clue in the docs */ + case SIS5595_BYTE: case SIS5595_BYTE_DATA: data->byte = sis5595_read(SMB_BYTE); break; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 5fd734f99ee9..3765dd7f450f 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -136,7 +136,7 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&adap->dev, "Successfull!\n"); + dev_dbg(&adap->dev, "Successful!\n"); } } diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index c2a9f8c94f5e..d08eeec53913 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -33,7 +33,7 @@ static unsigned short chip_addr[MAX_CHIPS]; module_param_array(chip_addr, ushort, NULL, S_IRUGO); MODULE_PARM_DESC(chip_addr, - "Chip addresses (up to 10, between 0x03 and 0x77)\n"); + "Chip addresses (up to 10, between 0x03 and 0x77)"); struct stub_chip { u8 pointer; diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index 1b0cfd5472fd..de9db49e54d9 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -51,7 +51,6 @@ struct taos_data { /* TAOS TSL2550 EVM */ static struct i2c_board_info tsl2550_info = { I2C_BOARD_INFO("tsl2550", 0x39), - .type = "tsl2550", }; /* Instantiate i2c devices based on the adapter name */ @@ -59,7 +58,7 @@ static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter) { if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) { dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n", - tsl2550_info.driver_name, tsl2550_info.addr); + tsl2550_info.type, tsl2550_info.addr); return i2c_new_device(adapter, &tsl2550_info); } diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c index 9e94542c18a2..23be4d42cb02 100644 --- a/drivers/i2c/chips/ds1682.c +++ b/drivers/i2c/chips/ds1682.c @@ -200,7 +200,8 @@ static struct bin_attribute ds1682_eeprom_attr = { /* * Called when a ds1682 device is matched with this driver */ -static int ds1682_probe(struct i2c_client *client) +static int ds1682_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int rc; @@ -234,12 +235,19 @@ static int ds1682_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id ds1682_id[] = { + { "ds1682", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1682_id); + static struct i2c_driver ds1682_driver = { .driver = { .name = "ds1682", }, .probe = ds1682_probe, .remove = ds1682_remove, + .id_table = ds1682_id, }; static int __init ds1682_init(void) diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c index 2dea0123a958..b36db1797c11 100644 --- a/drivers/i2c/chips/menelaus.c +++ b/drivers/i2c/chips/menelaus.c @@ -1149,7 +1149,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) static struct i2c_driver menelaus_i2c_driver; -static int menelaus_probe(struct i2c_client *client) +static int menelaus_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct menelaus_chip *menelaus; int rev = 0, val; @@ -1242,12 +1243,19 @@ static int __exit menelaus_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id menelaus_id[] = { + { "menelaus", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, menelaus_id); + static struct i2c_driver menelaus_i2c_driver = { .driver = { .name = DRIVER_NAME, }, .probe = menelaus_probe, .remove = __exit_p(menelaus_remove), + .id_table = menelaus_id, }; static int __init menelaus_init(void) diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index b67f69c2e7f3..85949685191b 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -64,7 +64,6 @@ static struct i2c_driver tps65010_driver; * as part of board setup by a bootloader. */ enum tps_model { - TPS_UNKNOWN = 0, TPS65010, TPS65011, TPS65012, @@ -527,11 +526,13 @@ static int __exit tps65010_remove(struct i2c_client *client) flush_scheduled_work(); debugfs_remove(tps->file); kfree(tps); + i2c_set_clientdata(client, NULL); the_tps = NULL; return 0; } -static int tps65010_probe(struct i2c_client *client) +static int tps65010_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tps65010 *tps; int status; @@ -552,20 +553,7 @@ static int tps65010_probe(struct i2c_client *client) mutex_init(&tps->lock); INIT_DELAYED_WORK(&tps->work, tps65010_work); tps->client = client; - - if (strcmp(client->name, "tps65010") == 0) - tps->model = TPS65010; - else if (strcmp(client->name, "tps65011") == 0) - tps->model = TPS65011; - else if (strcmp(client->name, "tps65012") == 0) - tps->model = TPS65012; - else if (strcmp(client->name, "tps65013") == 0) - tps->model = TPS65013; - else { - dev_warn(&client->dev, "unknown chip '%s'\n", client->name); - status = -ENODEV; - goto fail1; - } + tps->model = id->driver_data; /* the IRQ is active low, but many gpio lines can't support that * so this driver uses falling-edge triggers instead. @@ -594,9 +582,6 @@ static int tps65010_probe(struct i2c_client *client) case TPS65012: tps->por = 1; break; - case TPS_UNKNOWN: - printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); - break; /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ } tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG); @@ -615,6 +600,7 @@ static int tps65010_probe(struct i2c_client *client) i2c_smbus_read_byte_data(client, TPS_DEFGPIO), i2c_smbus_read_byte_data(client, TPS_MASK3)); + i2c_set_clientdata(client, tps); the_tps = tps; #if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) @@ -682,12 +668,22 @@ fail1: return status; } +static const struct i2c_device_id tps65010_id[] = { + { "tps65010", TPS65010 }, + { "tps65011", TPS65011 }, + { "tps65012", TPS65012 }, + { "tps65013", TPS65013 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tps65010_id); + static struct i2c_driver tps65010_driver = { .driver = { .name = "tps65010", }, .probe = tps65010_probe, .remove = __exit_p(tps65010_remove), + .id_table = tps65010_id, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c index a10fd2791a69..1a9cc135219f 100644 --- a/drivers/i2c/chips/tsl2550.c +++ b/drivers/i2c/chips/tsl2550.c @@ -364,7 +364,8 @@ static int tsl2550_init_client(struct i2c_client *client) */ static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client) +static int __devinit tsl2550_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct tsl2550_data *data; @@ -451,6 +452,12 @@ static int tsl2550_resume(struct i2c_client *client) #endif /* CONFIG_PM */ +static const struct i2c_device_id tsl2550_id[] = { + { "tsl2550", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsl2550_id); + static struct i2c_driver tsl2550_driver = { .driver = { .name = TSL2550_DRV_NAME, @@ -460,6 +467,7 @@ static struct i2c_driver tsl2550_driver = { .resume = tsl2550_resume, .probe = tsl2550_probe, .remove = __devexit_p(tsl2550_remove), + .id_table = tsl2550_id, }; static int __init tsl2550_init(void) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 6c7fa8d53c0e..26384daccb96 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,6 +48,17 @@ static DEFINE_IDR(i2c_adapter_idr); /* ------------------------------------------------------------------------- */ +static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, + const struct i2c_client *client) +{ + while (id->name[0]) { + if (strcmp(client->name, id->name) == 0) + return id; + id++; + } + return NULL; +} + static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = to_i2c_client(dev); @@ -59,6 +70,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (!is_newstyle_driver(driver)) return 0; + /* match on an id table if there is one */ + if (driver->id_table) + return i2c_match_id(driver->id_table, client) != NULL; + /* new style drivers use the same kind of driver matching policy * as platform devices or SPI: compare device and driver IDs. */ @@ -73,11 +88,17 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) struct i2c_client *client = to_i2c_client(dev); /* by definition, legacy drivers can't hotplug */ - if (dev->driver || !client->driver_name) + if (dev->driver) return 0; - if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) - return -ENOMEM; + if (client->driver_name[0]) { + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) + return -ENOMEM; + } else { + if (add_uevent_var(env, "MODALIAS=%s%s", + I2C_MODULE_PREFIX, client->name)) + return -ENOMEM; + } dev_dbg(dev, "uevent\n"); return 0; } @@ -90,13 +111,19 @@ static int i2c_device_probe(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(dev->driver); + const struct i2c_device_id *id; int status; if (!driver->probe) return -ENODEV; client->driver = driver; dev_dbg(dev, "probe\n"); - status = driver->probe(client); + + if (driver->id_table) + id = i2c_match_id(driver->id_table, client); + else + id = NULL; + status = driver->probe(client, id); if (status) client->driver = NULL; return status; @@ -179,9 +206,9 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); - return client->driver_name + return client->driver_name[0] ? sprintf(buf, "%s\n", client->driver_name) - : 0; + : sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } static struct device_attribute i2c_dev_attrs[] = { @@ -300,15 +327,21 @@ void i2c_unregister_device(struct i2c_client *client) EXPORT_SYMBOL_GPL(i2c_unregister_device); -static int dummy_nop(struct i2c_client *client) +static int dummy_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return 0; +} + +static int dummy_remove(struct i2c_client *client) { return 0; } static struct i2c_driver dummy_driver = { .driver.name = "dummy", - .probe = dummy_nop, - .remove = dummy_nop, + .probe = dummy_probe, + .remove = dummy_remove, }; /** diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3f9e10001e19..f702f9152ce6 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -862,40 +862,6 @@ config BLK_DEV_IDE_BAST Say Y here if you want to support the onboard IDE channels on the Simtec BAST or the Thorcom VR1000 -config ETRAX_IDE - tristate "ETRAX IDE support" - depends on CRIS && BROKEN - select BLK_DEV_IDEDMA - help - Enables the ETRAX IDE driver. - - You can't use parallel ports or SCSI ports at the same time. - -config ETRAX_IDE_DELAY - int "Delay for drives to regain consciousness" - depends on ETRAX_IDE && ETRAX_ARCH_V10 - default 15 - help - Number of seconds to wait for IDE drives to spin up after an IDE - reset. - -choice - prompt "IDE reset pin" - depends on ETRAX_IDE && ETRAX_ARCH_V10 - default ETRAX_IDE_PB7_RESET - -config ETRAX_IDE_PB7_RESET - bool "Port_PB_Bit_7" - help - IDE reset on pin 7 on port B - -config ETRAX_IDE_G27_RESET - bool "Port_G_Bit_27" - help - IDE reset on pin 27 on port G - -endchoice - config IDE_H8300 tristate "H8300 IDE support" depends on H8300 diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 571544c37bb2..f94b679b611e 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -35,7 +35,7 @@ ifeq ($(CONFIG_BLK_DEV_CMD640), y) obj-y += cmd640-core.o endif -obj-$(CONFIG_BLK_DEV_IDE) += cris/ ppc/ +obj-$(CONFIG_BLK_DEV_IDE) += ppc/ obj-$(CONFIG_IDE_H8300) += h8300/ obj-$(CONFIG_IDE_GENERIC) += ide-generic.o obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 124445c20921..061456914ca3 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -419,17 +419,19 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e hwif = ide_find_port(); if (hwif) { - int i; - /* * Ensure we're using MMIO */ default_hwif_mmiops(hwif); - for (i = 0; i <= 7; i++) { - hwif->io_ports_array[i] = port; - port += 1 << info->stepping; - } + hwif->io_ports.data_addr = port; + hwif->io_ports.error_addr = port + (1 << info->stepping); + hwif->io_ports.nsect_addr = port + (2 << info->stepping); + hwif->io_ports.lbal_addr = port + (3 << info->stepping); + hwif->io_ports.lbam_addr = port + (4 << info->stepping); + hwif->io_ports.lbah_addr = port + (5 << info->stepping); + hwif->io_ports.device_addr = port + (6 << info->stepping); + hwif->io_ports.status_addr = port + (7 << info->stepping); hwif->io_ports.ctl_addr = (unsigned long)base + info->ctrloffset; hwif->irq = ec->irq; @@ -481,7 +483,7 @@ static const struct ide_port_info icside_v6_port_info __initdata = { .init_dma = icside_dma_off_init, .port_ops = &icside_v6_no_dma_port_ops, .dma_ops = &icside_v6_dma_ops, - .host_flags = IDE_HFLAG_SERIALIZE, + .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, .mwdma_mask = ATA_MWDMA2, .swdma_mask = ATA_SWDMA2, }; diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index aaf32541622d..96378ebfb31f 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -342,6 +342,7 @@ static const struct ide_port_ops palm_bk3710_ports_ops = { static const struct ide_port_info __devinitdata palm_bk3710_port_info = { .init_dma = palm_bk3710_init_dma, .port_ops = &palm_bk3710_ports_ops, + .host_flags = IDE_HFLAG_MMIO, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA4, /* (input clk 99MHz) */ .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index babc1a5e128d..1747b2358775 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -53,6 +53,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id) ide_init_port_hw(hwif, &hw); + hwif->host_flags = IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); idx[0] = hwif->index; diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile deleted file mode 100644 index 20b95960531f..000000000000 --- a/drivers/ide/cris/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_CFLAGS += -Idrivers/ide - -obj-$(CONFIG_IDE_ETRAX) += ide-cris.o diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c deleted file mode 100644 index 9df26855bc05..000000000000 --- a/drivers/ide/cris/ide-cris.c +++ /dev/null @@ -1,1086 +0,0 @@ -/* - * Etrax specific IDE functions, like init and PIO-mode setting etc. - * Almost the entire ide.c is used for the rest of the Etrax ATA driver. - * Copyright (c) 2000-2005 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Mikael Starvik (crisv32 port) - */ - -/* Regarding DMA: - * - * There are two forms of DMA - "DMA handshaking" between the interface and the drive, - * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's - * something built-in in the Etrax. However only some drives support the DMA-mode handshaking - * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the - * device can't do DMA handshaking for some stupid reason. We don't need to do that. - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <asm/dma.h> - -/* number of DMA descriptors */ -#define MAX_DMA_DESCRS 64 - -/* number of times to retry busy-flags when reading/writing IDE-registers - * this can't be too high because a hung harddisk might cause the watchdog - * to trigger (sometimes INB and OUTB are called with irq's disabled) - */ - -#define IDE_REGISTER_TIMEOUT 300 - -#define LOWDB(x) -#define D(x) - -enum /* Transfer types */ -{ - TYPE_PIO, - TYPE_DMA, - TYPE_UDMA -}; - -/* CRISv32 specifics */ -#ifdef CONFIG_ETRAX_ARCH_V32 -#include <asm/arch/hwregs/ata_defs.h> -#include <asm/arch/hwregs/dma_defs.h> -#include <asm/arch/hwregs/dma.h> -#include <asm/arch/pinmux.h> - -#define ATA_UDMA2_CYC 2 -#define ATA_UDMA2_DVS 3 -#define ATA_UDMA1_CYC 2 -#define ATA_UDMA1_DVS 4 -#define ATA_UDMA0_CYC 4 -#define ATA_UDMA0_DVS 6 -#define ATA_DMA2_STROBE 7 -#define ATA_DMA2_HOLD 1 -#define ATA_DMA1_STROBE 8 -#define ATA_DMA1_HOLD 3 -#define ATA_DMA0_STROBE 25 -#define ATA_DMA0_HOLD 19 -#define ATA_PIO4_SETUP 3 -#define ATA_PIO4_STROBE 7 -#define ATA_PIO4_HOLD 1 -#define ATA_PIO3_SETUP 3 -#define ATA_PIO3_STROBE 9 -#define ATA_PIO3_HOLD 3 -#define ATA_PIO2_SETUP 3 -#define ATA_PIO2_STROBE 13 -#define ATA_PIO2_HOLD 5 -#define ATA_PIO1_SETUP 5 -#define ATA_PIO1_STROBE 23 -#define ATA_PIO1_HOLD 9 -#define ATA_PIO0_SETUP 9 -#define ATA_PIO0_STROBE 39 -#define ATA_PIO0_HOLD 9 - -int -cris_ide_ack_intr(ide_hwif_t* hwif) -{ - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, - hwif->io_ports.data_addr); - REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel); - return 1; -} - -static inline int -cris_ide_busy(void) -{ - reg_ata_rs_stat_data stat_data; - stat_data = REG_RD(ata, regi_ata, rs_stat_data); - return stat_data.busy; -} - -static inline int -cris_ide_ready(void) -{ - return !cris_ide_busy(); -} - -static inline int -cris_ide_data_available(unsigned short* data) -{ - reg_ata_rs_stat_data stat_data; - stat_data = REG_RD(ata, regi_ata, rs_stat_data); - *data = stat_data.data; - return stat_data.dav; -} - -static void -cris_ide_write_command(unsigned long command) -{ - REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */ -} - -static void -cris_ide_set_speed(int type, int setup, int strobe, int hold) -{ - reg_ata_rw_ctrl0 ctrl0 = REG_RD(ata, regi_ata, rw_ctrl0); - reg_ata_rw_ctrl1 ctrl1 = REG_RD(ata, regi_ata, rw_ctrl1); - - if (type == TYPE_PIO) { - ctrl0.pio_setup = setup; - ctrl0.pio_strb = strobe; - ctrl0.pio_hold = hold; - } else if (type == TYPE_DMA) { - ctrl0.dma_strb = strobe; - ctrl0.dma_hold = hold; - } else if (type == TYPE_UDMA) { - ctrl1.udma_tcyc = setup; - ctrl1.udma_tdvs = strobe; - } - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); - REG_WR(ata, regi_ata, rw_ctrl1, ctrl1); -} - -static unsigned long -cris_ide_base_address(int bus) -{ - reg_ata_rw_ctrl2 ctrl2 = {0}; - ctrl2.sel = bus; - return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2); -} - -static unsigned long -cris_ide_reg_addr(unsigned long addr, int cs0, int cs1) -{ - reg_ata_rw_ctrl2 ctrl2 = {0}; - ctrl2.addr = addr; - ctrl2.cs1 = cs1; - ctrl2.cs0 = cs0; - return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2); -} - -static __init void -cris_ide_reset(unsigned val) -{ - reg_ata_rw_ctrl0 ctrl0 = {0}; - ctrl0.rst = val ? regk_ata_active : regk_ata_inactive; - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); -} - -static __init void -cris_ide_init(void) -{ - reg_ata_rw_ctrl0 ctrl0 = {0}; - reg_ata_rw_intr_mask intr_mask = {0}; - - ctrl0.en = regk_ata_yes; - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); - - intr_mask.bus0 = regk_ata_yes; - intr_mask.bus1 = regk_ata_yes; - intr_mask.bus2 = regk_ata_yes; - intr_mask.bus3 = regk_ata_yes; - - REG_WR(ata, regi_ata, rw_intr_mask, intr_mask); - - crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata); - crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata); - - crisv32_pinmux_alloc_fixed(pinmux_ata); - crisv32_pinmux_alloc_fixed(pinmux_ata0); - crisv32_pinmux_alloc_fixed(pinmux_ata1); - crisv32_pinmux_alloc_fixed(pinmux_ata2); - crisv32_pinmux_alloc_fixed(pinmux_ata3); - - DMA_RESET(regi_dma2); - DMA_ENABLE(regi_dma2); - DMA_RESET(regi_dma3); - DMA_ENABLE(regi_dma3); - - DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2); - DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2); -} - -static dma_descr_context mycontext __attribute__ ((__aligned__(32))); - -#define cris_dma_descr_type dma_descr_data -#define cris_pio_read regk_ata_rd -#define cris_ultra_mask 0x7 -#define MAX_DESCR_SIZE 0xffffffffUL - -static unsigned long -cris_ide_get_reg(unsigned long reg) -{ - return (reg & 0x0e000000) >> 25; -} - -static void -cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last) -{ - d->buf = (char*)virt_to_phys(buf); - d->after = d->buf + len; - d->eol = last; -} - -static void -cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir,int type,int len) -{ - ide_hwif_t *hwif = drive->hwif; - - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, - hwif->io_ports.data_addr); - reg_ata_rw_trf_cnt trf_cnt = {0}; - - mycontext.saved_data = (dma_descr_data*)virt_to_phys(d); - mycontext.saved_data_buf = d->buf; - /* start the dma channel */ - DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext)); - - /* initiate a multi word dma read using PIO handshaking */ - trf_cnt.cnt = len >> 1; - /* Due to a "feature" the transfer count has to be one extra word for UDMA. */ - if (type == TYPE_UDMA) - trf_cnt.cnt++; - REG_WR(ata, regi_ata, rw_trf_cnt, trf_cnt); - - ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr; - ctrl2.trf_mode = regk_ata_dma; - ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio : - type == TYPE_DMA ? regk_ata_dma : regk_ata_udma; - ctrl2.multi = regk_ata_yes; - ctrl2.dma_size = regk_ata_word; - REG_WR(ata, regi_ata, rw_ctrl2, ctrl2); -} - -static void -cris_ide_wait_dma(int dir) -{ - reg_dma_rw_stat status; - do - { - status = REG_RD(dma, dir ? regi_dma3 : regi_dma2, rw_stat); - } while(status.list_state != regk_dma_data_at_eol); -} - -static int cris_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - int intr = REG_RD_INT(ata, regi_ata, r_intr); - - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, - hwif->io_ports.data_addr); - - return intr & (1 << ctrl2.sel) ? 1 : 0; -} - -static void cris_ide_initialize_dma(int dir) -{ -} - -#else -/* CRISv10 specifics */ -#include <asm/arch/svinto.h> -#include <asm/arch/io_interface_mux.h> - -/* PIO timing (in R_ATA_CONFIG) - * - * _____________________________ - * ADDRESS : ________/ - * - * _______________ - * DIOR : ____________/ \__________ - * - * _______________ - * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX - * - * - * DIOR is unbuffered while address and data is buffered. - * This creates two problems: - * 1. The DIOR pulse is to early (because it is unbuffered) - * 2. The rise time of DIOR is long - * - * There are at least three different plausible solutions - * 1. Use a pad capable of larger currents in Etrax - * 2. Use an external buffer - * 3. Make the strobe pulse longer - * - * Some of the strobe timings below are modified to compensate - * for this. This implies a slight performance decrease. - * - * THIS SHOULD NEVER BE CHANGED! - * - * TODO: Is this true for the latest LX boards still ? - */ - -#define ATA_UDMA2_CYC 0 /* No UDMA supported, just to make it compile. */ -#define ATA_UDMA2_DVS 0 -#define ATA_UDMA1_CYC 0 -#define ATA_UDMA1_DVS 0 -#define ATA_UDMA0_CYC 0 -#define ATA_UDMA0_DVS 0 -#define ATA_DMA2_STROBE 4 -#define ATA_DMA2_HOLD 0 -#define ATA_DMA1_STROBE 4 -#define ATA_DMA1_HOLD 1 -#define ATA_DMA0_STROBE 12 -#define ATA_DMA0_HOLD 9 -#define ATA_PIO4_SETUP 1 -#define ATA_PIO4_STROBE 5 -#define ATA_PIO4_HOLD 0 -#define ATA_PIO3_SETUP 1 -#define ATA_PIO3_STROBE 5 -#define ATA_PIO3_HOLD 1 -#define ATA_PIO2_SETUP 1 -#define ATA_PIO2_STROBE 6 -#define ATA_PIO2_HOLD 2 -#define ATA_PIO1_SETUP 2 -#define ATA_PIO1_STROBE 11 -#define ATA_PIO1_HOLD 4 -#define ATA_PIO0_SETUP 4 -#define ATA_PIO0_STROBE 19 -#define ATA_PIO0_HOLD 4 - -int -cris_ide_ack_intr(ide_hwif_t* hwif) -{ - return 1; -} - -static inline int -cris_ide_busy(void) -{ - return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ; -} - -static inline int -cris_ide_ready(void) -{ - return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ; -} - -static inline int -cris_ide_data_available(unsigned short* data) -{ - unsigned long status = *R_ATA_STATUS_DATA; - *data = (unsigned short)status; - return status & IO_MASK(R_ATA_STATUS_DATA, dav); -} - -static void -cris_ide_write_command(unsigned long command) -{ - *R_ATA_CTRL_DATA = command; -} - -static void -cris_ide_set_speed(int type, int setup, int strobe, int hold) -{ - static int pio_setup = ATA_PIO4_SETUP; - static int pio_strobe = ATA_PIO4_STROBE; - static int pio_hold = ATA_PIO4_HOLD; - static int dma_strobe = ATA_DMA2_STROBE; - static int dma_hold = ATA_DMA2_HOLD; - - if (type == TYPE_PIO) { - pio_setup = setup; - pio_strobe = strobe; - pio_hold = hold; - } else if (type == TYPE_DMA) { - dma_strobe = strobe; - dma_hold = hold; - } - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, dma_strobe ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, dma_hold ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, pio_setup ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, pio_strobe ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, pio_hold ) ); -} - -static unsigned long -cris_ide_base_address(int bus) -{ - return IO_FIELD(R_ATA_CTRL_DATA, sel, bus); -} - -static unsigned long -cris_ide_reg_addr(unsigned long addr, int cs0, int cs1) -{ - return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) | - IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) | - IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1); -} - -static __init void -cris_ide_reset(unsigned val) -{ -#ifdef CONFIG_ETRAX_IDE_G27_RESET - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val); -#endif -#ifdef CONFIG_ETRAX_IDE_PB7_RESET - port_pb_dir_shadow = port_pb_dir_shadow | - IO_STATE(R_PORT_PB_DIR, dir7, output); - *R_PORT_PB_DIR = port_pb_dir_shadow; - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, val); -#endif -} - -static __init void -cris_ide_init(void) -{ - volatile unsigned int dummy; - - *R_ATA_CTRL_DATA = 0; - *R_ATA_TRANSFER_CNT = 0; - *R_ATA_CONFIG = 0; - - if (cris_request_io_interface(if_ata, "ETRAX100LX IDE")) { - printk(KERN_CRIT "ide: Failed to get IO interface\n"); - return; - } else if (cris_request_dma(ATA_TX_DMA_NBR, - "ETRAX100LX IDE TX", - DMA_VERBOSE_ON_ERROR, - dma_ata)) { - cris_free_io_interface(if_ata); - printk(KERN_CRIT "ide: Failed to get Tx DMA channel\n"); - return; - } else if (cris_request_dma(ATA_RX_DMA_NBR, - "ETRAX100LX IDE RX", - DMA_VERBOSE_ON_ERROR, - dma_ata)) { - cris_free_dma(ATA_TX_DMA_NBR, "ETRAX100LX IDE Tx"); - cris_free_io_interface(if_ata); - printk(KERN_CRIT "ide: Failed to get Rx DMA channel\n"); - return; - } - - /* make a dummy read to set the ata controller in a proper state */ - dummy = *R_ATA_STATUS_DATA; - - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 )); - *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) | - IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) ); - - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/ - - *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); - - /* reset the dma channels we will use */ - - RESET_DMA(ATA_TX_DMA_NBR); - RESET_DMA(ATA_RX_DMA_NBR); - WAIT_DMA(ATA_TX_DMA_NBR); - WAIT_DMA(ATA_RX_DMA_NBR); -} - -#define cris_dma_descr_type etrax_dma_descr -#define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read) -#define cris_ultra_mask 0x0 -#define MAX_DESCR_SIZE 0x10000UL - -static unsigned long -cris_ide_get_reg(unsigned long reg) -{ - return (reg & 0x0e000000) >> 25; -} - -static void -cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last) -{ - d->buf = virt_to_phys(buf); - d->sw_len = len == MAX_DESCR_SIZE ? 0 : len; - if (last) - d->ctrl |= d_eol; -} - -static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len) -{ - unsigned long cmd; - - if (dir) { - /* need to do this before RX DMA due to a chip bug - * it is enough to just flush the part of the cache that - * corresponds to the buffers we start, but since HD transfers - * usually are more than 8 kB, it is easier to optimize for the - * normal case and just flush the entire cache. its the only - * way to be sure! (OB movie quote) - */ - flush_etrax_cache(); - *R_DMA_CH3_FIRST = virt_to_phys(d); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - } else { - *R_DMA_CH2_FIRST = virt_to_phys(d); - *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); - } - - /* initiate a multi word dma read using DMA handshaking */ - - *R_ATA_TRANSFER_CNT = - IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1); - - cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write); - cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) : - IO_STATE(R_ATA_CTRL_DATA, handsh, dma); - *R_ATA_CTRL_DATA = - cmd | - IO_FIELD(R_ATA_CTRL_DATA, data, - drive->hwif->io_ports.data_addr) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); -} - -static void -cris_ide_wait_dma(int dir) -{ - if (dir) - WAIT_DMA(ATA_RX_DMA_NBR); - else - WAIT_DMA(ATA_TX_DMA_NBR); -} - -static int cris_dma_test_irq(ide_drive_t *drive) -{ - int intr = *R_IRQ_MASK0_RD; - int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel, - drive->hwif->io_ports.data_addr); - - return intr & (1 << (bus + IO_BITNR(R_IRQ_MASK0_RD, ata_irq0))) ? 1 : 0; -} - - -static void cris_ide_initialize_dma(int dir) -{ - if (dir) - { - RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_RX_DMA_NBR); - } - else - { - RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_TX_DMA_NBR); - } -} - -#endif - -void -cris_ide_outw(unsigned short data, unsigned long reg) { - int timeleft; - - LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg)); - - /* note the lack of handling any timeouts. we stop waiting, but we don't - * really notify anybody. - */ - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for busy flag */ - do { - timeleft--; - } while(timeleft && cris_ide_busy()); - - /* - * Fall through at a timeout, so the ongoing command will be - * aborted by the write below, which is expected to be a dummy - * command to the command register. This happens when a faulty - * drive times out on a command. See comment on timeout in - * INB. - */ - if(!timeleft) - printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data); - - cris_ide_write_command(reg|data); /* write data to the drive's register */ - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for transmitter ready */ - do { - timeleft--; - } while(timeleft && !cris_ide_ready()); -} - -void -cris_ide_outb(unsigned char data, unsigned long reg) -{ - cris_ide_outw(data, reg); -} - -void -cris_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port) -{ - cris_ide_outw(addr, port); -} - -unsigned short -cris_ide_inw(unsigned long reg) { - int timeleft; - unsigned short val; - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for busy flag */ - do { - timeleft--; - } while(timeleft && cris_ide_busy()); - - if(!timeleft) { - /* - * If we're asked to read the status register, like for - * example when a command does not complete for an - * extended time, but the ATA interface is stuck in a - * busy state at the *ETRAX* ATA interface level (as has - * happened repeatedly with at least one bad disk), then - * the best thing to do is to pretend that we read - * "busy" in the status register, so the IDE driver will - * time-out, abort the ongoing command and perform a - * reset sequence. Note that the subsequent OUT_BYTE - * call will also timeout on busy, but as long as the - * write is still performed, everything will be fine. - */ - if (cris_ide_get_reg(reg) == 7) - return BUSY_STAT; - else - /* For other rare cases we assume 0 is good enough. */ - return 0; - } - - cris_ide_write_command(reg | cris_pio_read); - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for available */ - do { - timeleft--; - } while(timeleft && !cris_ide_data_available(&val)); - - if(!timeleft) - return 0; - - LOWDB(printk("inb: 0x%x from reg 0x%x\n", val & 0xff, reg)); - - return val; -} - -unsigned char -cris_ide_inb(unsigned long reg) -{ - return (unsigned char)cris_ide_inw(reg); -} - -static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int); -static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int); -static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); -static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); - -static void cris_dma_host_set(ide_drive_t *drive, int on) -{ -} - -static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - int setup, strobe, hold; - - switch(pio) - { - case 0: - setup = ATA_PIO0_SETUP; - strobe = ATA_PIO0_STROBE; - hold = ATA_PIO0_HOLD; - break; - case 1: - setup = ATA_PIO1_SETUP; - strobe = ATA_PIO1_STROBE; - hold = ATA_PIO1_HOLD; - break; - case 2: - setup = ATA_PIO2_SETUP; - strobe = ATA_PIO2_STROBE; - hold = ATA_PIO2_HOLD; - break; - case 3: - setup = ATA_PIO3_SETUP; - strobe = ATA_PIO3_STROBE; - hold = ATA_PIO3_HOLD; - break; - case 4: - setup = ATA_PIO4_SETUP; - strobe = ATA_PIO4_STROBE; - hold = ATA_PIO4_HOLD; - break; - default: - return; - } - - cris_ide_set_speed(TYPE_PIO, setup, strobe, hold); -} - -static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) -{ - int cyc = 0, dvs = 0, strobe = 0, hold = 0; - - switch(speed) - { - case XFER_UDMA_0: - cyc = ATA_UDMA0_CYC; - dvs = ATA_UDMA0_DVS; - break; - case XFER_UDMA_1: - cyc = ATA_UDMA1_CYC; - dvs = ATA_UDMA1_DVS; - break; - case XFER_UDMA_2: - cyc = ATA_UDMA2_CYC; - dvs = ATA_UDMA2_DVS; - break; - case XFER_MW_DMA_0: - strobe = ATA_DMA0_STROBE; - hold = ATA_DMA0_HOLD; - break; - case XFER_MW_DMA_1: - strobe = ATA_DMA1_STROBE; - hold = ATA_DMA1_HOLD; - break; - case XFER_MW_DMA_2: - strobe = ATA_DMA2_STROBE; - hold = ATA_DMA2_HOLD; - break; - } - - if (speed >= XFER_UDMA_0) - cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0); - else - cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); -} - -static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base) -{ - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = 0; i <= 7; i++) - hw->io_ports_array[i] = base + cris_ide_reg_addr(i, 0, 1); - - /* - * the IDE control register is at ATA address 6, - * with CS1 active instead of CS0 - */ - hw->io_ports.ctl_addr = base + cris_ide_reg_addr(6, 1, 0); - - hw->irq = ide_default_irq(0); - hw->ack_intr = cris_ide_ack_intr; -} - -static const struct ide_port_ops cris_port_ops = { - .set_pio_mode = cris_set_pio_mode, - .set_dma_mode = cris_set_dma_mode, -}; - -static const struct ide_dma_ops cris_dma_ops; - -static const struct ide_port_info cris_port_info __initdata = { - .chipset = ide_etrax100, - .port_ops = &cris_port_ops, - .dma_ops = &cris_dma_ops, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_NO_DMA, /* no SFF-style DMA */ - .pio_mask = ATA_PIO4, - .udma_mask = cris_ultra_mask, - .mwdma_mask = ATA_MWDMA2, -}; - -static int __init init_e100_ide(void) -{ - hw_regs_t hw; - int h; - u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; - - printk("ide: ETRAX FS built-in ATA DMA controller\n"); - - for (h = 0; h < 4; h++) { - ide_hwif_t *hwif = NULL; - - cris_setup_ports(&hw, cris_ide_base_address(h)); - - hwif = ide_find_port(); - if (hwif == NULL) - continue; - ide_init_port_data(hwif, hwif->index); - ide_init_port_hw(hwif, &hw); - - hwif->ata_input_data = &cris_ide_input_data; - hwif->ata_output_data = &cris_ide_output_data; - hwif->atapi_input_bytes = &cris_atapi_input_bytes; - hwif->atapi_output_bytes = &cris_atapi_output_bytes; - hwif->OUTB = &cris_ide_outb; - hwif->OUTW = &cris_ide_outw; - hwif->OUTBSYNC = &cris_ide_outbsync; - hwif->INB = &cris_ide_inb; - hwif->INW = &cris_ide_inw; - hwif->cbl = ATA_CBL_PATA40; - - idx[h] = hwif->index; - } - - /* Reset pulse */ - cris_ide_reset(0); - udelay(25); - cris_ide_reset(1); - - cris_ide_init(); - - cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD); - cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD); - cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0); - - ide_device_add(idx, &cris_port_info); - - return 0; -} - -static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16))); - -/* - * The following routines are mainly used by the ATAPI drivers. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ -static void -cris_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - D(printk("atapi_input_bytes, buffer 0x%x, count %d\n", - buffer, bytecount)); - - if(bytecount & 1) { - printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount); - bytecount++; /* to round off */ - } - - /* setup DMA and start transfer */ - - cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1); - cris_ide_start_dma(drive, &mydescr, 1, TYPE_PIO, bytecount); - - /* wait for completion */ - LED_DISK_READ(1); - cris_ide_wait_dma(1); - LED_DISK_READ(0); -} - -static void -cris_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - D(printk("atapi_output_bytes, buffer 0x%x, count %d\n", - buffer, bytecount)); - - if(bytecount & 1) { - printk("odd bytecount %d in atapi_out_bytes!\n", bytecount); - bytecount++; - } - - cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1); - cris_ide_start_dma(drive, &mydescr, 0, TYPE_PIO, bytecount); - - /* wait for completion */ - - LED_DISK_WRITE(1); - LED_DISK_READ(1); - cris_ide_wait_dma(0); - LED_DISK_WRITE(0); -} - -/* - * This is used for most PIO data transfers *from* the IDE interface - */ -static void -cris_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - cris_atapi_input_bytes(drive, buffer, wcount << 2); -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -static void -cris_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - cris_atapi_output_bytes(drive, buffer, wcount << 2); -} - -/* we only have one DMA channel on the chip for ATA, so we can keep these statically */ -static cris_dma_descr_type ata_descrs[MAX_DMA_DESCRS] __attribute__ ((__aligned__(16))); -static unsigned int ata_tot_size; - -/* - * cris_ide_build_dmatable() prepares a dma request. - * Returns 0 if all went okay, returns 1 otherwise. - */ -static int cris_ide_build_dmatable (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct scatterlist* sg; - struct request *rq = drive->hwif->hwgroup->rq; - unsigned long size, addr; - unsigned int count = 0; - int i = 0; - - sg = hwif->sg_table; - - ata_tot_size = 0; - - ide_map_sg(drive, rq); - i = hwif->sg_nents; - - while(i) { - /* - * Determine addr and size of next buffer area. We assume that - * individual virtual buffers are always composed linearly in - * physical memory. For example, we assume that any 8kB buffer - * is always composed of two adjacent physical 4kB pages rather - * than two possibly non-adjacent physical 4kB pages. - */ - /* group sequential buffers into one large buffer */ - addr = sg_phys(sg); - size = sg_dma_len(sg); - while (--i) { - sg = sg_next(sg); - if ((addr + size) != sg_phys(sg)) - break; - size += sg_dma_len(sg); - } - - /* did we run out of descriptors? */ - - if(count >= MAX_DMA_DESCRS) { - printk("%s: too few DMA descriptors\n", drive->name); - return 1; - } - - /* however, this case is more difficult - rw_trf_cnt cannot be more - than 65536 words per transfer, so in that case we need to either - 1) use a DMA interrupt to re-trigger rw_trf_cnt and continue with - the descriptors, or - 2) simply do the request here, and get dma_intr to only ide_end_request on - those blocks that were actually set-up for transfer. - */ - - if(ata_tot_size + size > 131072) { - printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size); - return 1; - } - - /* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. Since we - don't handle size > 131072 only one split is necessary */ - - if(size > MAX_DESCR_SIZE) { - cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, MAX_DESCR_SIZE, 0); - count++; - ata_tot_size += MAX_DESCR_SIZE; - size -= MAX_DESCR_SIZE; - addr += MAX_DESCR_SIZE; - } - - cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, size,i ? 0 : 1); - count++; - ata_tot_size += size; - } - - if (count) { - /* return and say all is ok */ - return 0; - } - - printk("%s: empty DMA table?\n", drive->name); - return 1; /* let the PIO routines handle this weirdness */ -} - -/* - * cris_dma_intr() is the handler for disk read/write DMA interrupts - */ -static ide_startstop_t cris_dma_intr (ide_drive_t *drive) -{ - LED_DISK_READ(0); - LED_DISK_WRITE(0); - - return ide_dma_intr(drive); -} - -/* - * Functions below initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * For ATAPI devices, we just prepare for DMA and return. The caller should - * then issue the packet command to the drive and call us again with - * cris_dma_start afterwards. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case - * the caller should revert to PIO for the current request. - */ - -static int cris_dma_end(ide_drive_t *drive) -{ - drive->waiting_for_dma = 0; - return 0; -} - -static int cris_dma_setup(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->hwgroup->rq; - - cris_ide_initialize_dma(!rq_data_dir(rq)); - if (cris_ide_build_dmatable (drive)) { - ide_map_sg(drive, rq); - return 1; - } - - drive->waiting_for_dma = 1; - return 0; -} - -static void cris_dma_exec_cmd(ide_drive_t *drive, u8 command) -{ - ide_execute_command(drive, command, &cris_dma_intr, WAIT_CMD, NULL); -} - -static void cris_dma_start(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->hwgroup->rq; - int writing = rq_data_dir(rq); - int type = TYPE_DMA; - - if (drive->current_speed >= XFER_UDMA_0) - type = TYPE_UDMA; - - cris_ide_start_dma(drive, &ata_descrs[0], writing ? 0 : 1, type, ata_tot_size); - - if (writing) { - LED_DISK_WRITE(1); - } else { - LED_DISK_READ(1); - } -} - -static const struct ide_dma_ops cris_dma_ops = { - .dma_host_set = cris_dma_host_set, - .dma_setup = cris_dma_setup, - .dma_exec_cmd = cris_dma_exec_cmd, - .dma_start = cris_dma_start, - .dma_end = cris_dma_end, - .dma_test_irq = cris_dma_test_irq, -}; - -module_init(init_e100_ide); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index fd23f12e17aa..ecf53bb0d2aa 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -42,6 +42,91 @@ static u16 mm_inw(unsigned long a) return r; } +static void h8300_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + ide_set_irq(drive, 1); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) + mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void h8300_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = mm_inw(io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = inb(io_ports->lbah_addr); + } +} + static void mm_outsw(unsigned long addr, void *buf, u32 len) { unsigned short *bp = (unsigned short *)buf; @@ -56,6 +141,18 @@ static void mm_insw(unsigned long addr, void *buf, u32 len) *bp = bswap(*(volatile u16 *)addr); } +static void h8300_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + +static void h8300_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + #define H8300_IDE_GAP (2) static inline void hw_setup(hw_regs_t *hw) @@ -74,12 +171,11 @@ static inline void hwif_setup(ide_hwif_t *hwif) { default_hwif_iops(hwif); - hwif->OUTW = mm_outw; - hwif->OUTSW = mm_outsw; - hwif->INW = mm_inw; - hwif->INSW = mm_insw; - hwif->OUTSL = NULL; - hwif->INSL = NULL; + hwif->tf_load = h8300_tf_load; + hwif->tf_read = h8300_tf_read; + + hwif->input_data = h8300_input_data; + hwif->output_data = h8300_output_data; } static int __init h8300_ide_init(void) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index b34fd2bde96f..68e7f19dc036 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -142,7 +142,6 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, { unsigned long sector; unsigned long bio_sectors; - unsigned long valid; struct cdrom_info *info = drive->driver_data; if (!cdrom_log_sense(drive, failed_command, sense)) @@ -173,17 +172,13 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, (sense->information[2] << 8) | (sense->information[3]); - bio_sectors = bio_sectors(failed_command->bio); - if (bio_sectors < 4) - bio_sectors = 4; if (drive->queue->hardsect_size == 2048) /* device sector size is 2K */ sector <<= 2; + + bio_sectors = max(bio_sectors(failed_command->bio), 4U); sector &= ~(bio_sectors - 1); - valid = (sector - failed_command->sector) << 9; - if (valid < 0) - valid = 0; if (sector < get_capacity(info->disk) && drive->probed_capacity - sector < 4 * 75) set_capacity(info->disk, sector); @@ -555,14 +550,7 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } else { - unsigned long flags; - - /* packet command */ - spin_lock_irqsave(&ide_lock, flags); - hwif->OUTBSYNC(drive, WIN_PACKETCMD, - hwif->io_ports.command_addr); - ndelay(400); - spin_unlock_irqrestore(&ide_lock, flags); + ide_execute_pkt_cmd(drive); return (*handler) (drive); } @@ -613,7 +601,7 @@ static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive, cmd_len = ATAPI_MIN_CDB_BYTES; /* send the command to the device */ - HWIF(drive)->atapi_output_bytes(drive, rq->cmd, cmd_len); + hwif->output_data(drive, NULL, rq->cmd, cmd_len); /* start the DMA if need be */ if (info->dma) @@ -629,7 +617,7 @@ static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len) { while (len > 0) { int dum = 0; - xf(drive, &dum, sizeof(dum)); + xf(drive, NULL, &dum, sizeof(dum)); len -= sizeof(dum); } } @@ -639,7 +627,7 @@ static void ide_cd_drain_data(ide_drive_t *drive, int nsects) while (nsects > 0) { static char dum[SECTOR_SIZE]; - drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum)); + drive->hwif->input_data(drive, NULL, dum, sizeof(dum)); nsects--; } } @@ -666,7 +654,7 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq, printk(KERN_ERR "%s: %s: wrong transfer direction!\n", drive->name, __func__); - xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes; + xf = rw ? hwif->output_data : hwif->input_data; ide_cd_pad_transfer(drive, xf, len); } else if (rw == 0 && ireason == 1) { /* @@ -794,7 +782,7 @@ static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive) sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); rq->cmd[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]); @@ -1019,10 +1007,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (ireason == 0) { write = 1; - xferfunc = HWIF(drive)->atapi_output_bytes; + xferfunc = hwif->output_data; } else { write = 0; - xferfunc = HWIF(drive)->atapi_input_bytes; + xferfunc = hwif->input_data; } /* transfer data */ @@ -1061,7 +1049,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (blen > thislen) blen = thislen; - xferfunc(drive, ptr, blen); + xferfunc(drive, NULL, ptr, blen); thislen -= blen; len -= blen; @@ -1706,7 +1694,7 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) long block = (long)rq->hard_sector / (hard_sect >> 9); unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); if (rq_data_dir(rq) == READ) rq->cmd[0] = GPCMD_READ_10; diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c index 6ed7ca071331..6490a2dea96b 100644 --- a/drivers/ide/ide-cd_verbose.c +++ b/drivers/ide/ide-cd_verbose.c @@ -326,7 +326,7 @@ void ide_cd_log_error(const char *name, struct request *failed_command, printk(KERN_ERR " The failed \"%s\" packet command " "was: \n \"", s); - for (i = 0; i < sizeof(failed_command->cmd); i++) + for (i = 0; i < BLK_MAX_CDB; i++) printk(KERN_CONT "%02x ", failed_command->cmd[i]); printk(KERN_CONT "\"\n"); } diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index c352cf27b6e7..653b1ade13d3 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -464,9 +464,10 @@ int ide_dma_setup(ide_drive_t *drive) /* PRD table */ if (hwif->mmio) - writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable); + writel(hwif->dmatable_dma, + (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS)); else - outl(hwif->dmatable_dma, hwif->dma_prdtable); + outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS); /* specify r/w */ hwif->OUTB(reading, hwif->dma_command); @@ -858,14 +859,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base) if (!hwif->dma_command) hwif->dma_command = hwif->dma_base + 0; - if (!hwif->dma_vendor1) - hwif->dma_vendor1 = hwif->dma_base + 1; if (!hwif->dma_status) hwif->dma_status = hwif->dma_base + 2; - if (!hwif->dma_vendor3) - hwif->dma_vendor3 = hwif->dma_base + 3; - if (!hwif->dma_prdtable) - hwif->dma_prdtable = hwif->dma_base + 4; hwif->dma_ops = &sff_dma_ops; } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 489079b8ed03..f05fbc2bd7a8 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -231,6 +231,7 @@ static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs) static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount, int direction) { + ide_hwif_t *hwif = drive->hwif; struct request *rq = pc->rq; struct req_iterator iter; struct bio_vec *bvec; @@ -246,9 +247,9 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, data = bvec_kmap_irq(bvec, &flags); if (direction) - drive->hwif->atapi_output_bytes(drive, data, count); + hwif->output_data(drive, NULL, data, count); else - drive->hwif->atapi_input_bytes(drive, data, count); + hwif->input_data(drive, NULL, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; @@ -261,10 +262,7 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bcount) { printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n", drive->name, __func__, bcount); - if (direction) - ide_atapi_write_zeros(drive, bcount); - else - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, direction, bcount); } } @@ -490,7 +488,7 @@ static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive) printk(KERN_ERR "ide-floppy: The floppy wants " "to send us more data than expected " "- discarding data\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); ide_set_handler(drive, &idefloppy_pc_intr, @@ -503,12 +501,12 @@ static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive) } } if (pc->flags & PC_FLAG_WRITING) - xferfunc = hwif->atapi_output_bytes; + xferfunc = hwif->output_data; else - xferfunc = hwif->atapi_input_bytes; + xferfunc = hwif->input_data; if (pc->buf) - xferfunc(drive, pc->cur_pos, bcount); + xferfunc(drive, NULL, pc->cur_pos, bcount); else ide_floppy_io_buffers(drive, pc, bcount, !!(pc->flags & PC_FLAG_WRITING)); @@ -548,8 +546,10 @@ static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive) /* Set the interrupt routine */ ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); + /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12); + hwif->output_data(drive, NULL, floppy->pc->c, 12); + return ide_started; } @@ -569,7 +569,8 @@ static int idefloppy_transfer_pc2(ide_drive_t *drive) idefloppy_floppy_t *floppy = drive->driver_data; /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12); + drive->hwif->output_data(drive, NULL, floppy->pc->c, 12); + /* Timeout for the packet command */ return IDEFLOPPY_WAIT_CMD; } @@ -692,7 +693,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive, return ide_started; } else { /* Issue the packet command */ - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); + ide_execute_pkt_cmd(drive); return (*pkt_xfer_routine) (drive); } } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 3a2d8930d17f..696525342e9a 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -295,49 +295,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) spin_unlock_irqrestore(&ide_lock, flags); } -void ide_tf_read(ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_taskfile *tf = &task->tf; - - if (task->tf_flags & IDE_TFLAG_IN_DATA) { - u16 data = hwif->INW(io_ports->data_addr); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - - /* be sure we're looking at the low order bits */ - hwif->OUTB(drive->ctl & ~0x80, io_ports->ctl_addr); - - if (task->tf_flags & IDE_TFLAG_IN_NSECT) - tf->nsect = hwif->INB(io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAL) - tf->lbal = hwif->INB(io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAM) - tf->lbam = hwif->INB(io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAH) - tf->lbah = hwif->INB(io_ports->lbah_addr); - if (task->tf_flags & IDE_TFLAG_IN_DEVICE) - tf->device = hwif->INB(io_ports->device_addr); - - if (task->tf_flags & IDE_TFLAG_LBA48) { - hwif->OUTB(drive->ctl | 0x80, io_ports->ctl_addr); - - if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = hwif->INB(io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = hwif->INB(io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = hwif->INB(io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = hwif->INB(io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = hwif->INB(io_ports->lbah_addr); - } -} - /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -373,7 +330,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) tf->error = err; tf->status = stat; - ide_tf_read(drive, task); + drive->hwif->tf_read(drive, task); if (task->tf_flags & IDE_TFLAG_DYN) kfree(task); @@ -422,7 +379,7 @@ static void try_to_flush_leftover_data (ide_drive_t *drive) u32 wcount = (i > 16) ? 16 : i; i -= wcount; - HWIF(drive)->ata_input_data(drive, buffer, wcount); + drive->hwif->input_data(drive, NULL, buffer, wcount * 4); } } @@ -502,7 +459,8 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, WIN_IDLEIMMEDIATE, + hwif->io_ports.command_addr); if (rq->errors >= ERROR_MAX) { ide_kill_rq(drive, rq); @@ -1592,8 +1550,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) void ide_init_drive_cmd (struct request *rq) { - memset(rq, 0, sizeof(*rq)); - rq->ref_count = 1; + blk_rq_init(NULL, rq); } EXPORT_SYMBOL(ide_init_drive_cmd); @@ -1679,7 +1636,23 @@ void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma) task.tf.lbam = bcount & 0xff; task.tf.lbah = (bcount >> 8) & 0xff; - ide_tf_load(drive, &task); + ide_tf_dump(drive->name, &task.tf); + drive->hwif->tf_load(drive, &task); } EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load); + +void ide_pad_transfer(ide_drive_t *drive, int write, int len) +{ + ide_hwif_t *hwif = drive->hwif; + u8 buf[4] = { 0 }; + + while (len > 0) { + if (write) + hwif->output_data(drive, NULL, buf, min(4, len)); + else + hwif->input_data(drive, NULL, buf, min(4, len)); + len -= 4; + } +} +EXPORT_SYMBOL_GPL(ide_pad_transfer); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 5425d3038ec2..57d9a9a79a6f 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -37,21 +37,6 @@ static u8 ide_inb (unsigned long port) return (u8) inb(port); } -static u16 ide_inw (unsigned long port) -{ - return (u16) inw(port); -} - -static void ide_insw (unsigned long port, void *addr, u32 count) -{ - insw(port, addr, count); -} - -static void ide_insl (unsigned long port, void *addr, u32 count) -{ - insl(port, addr, count); -} - static void ide_outb (u8 val, unsigned long port) { outb(val, port); @@ -62,32 +47,11 @@ static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port) outb(addr, port); } -static void ide_outw (u16 val, unsigned long port) -{ - outw(val, port); -} - -static void ide_outsw (unsigned long port, void *addr, u32 count) -{ - outsw(port, addr, count); -} - -static void ide_outsl (unsigned long port, void *addr, u32 count) -{ - outsl(port, addr, count); -} - void default_hwif_iops (ide_hwif_t *hwif) { hwif->OUTB = ide_outb; hwif->OUTBSYNC = ide_outbsync; - hwif->OUTW = ide_outw; - hwif->OUTSW = ide_outsw; - hwif->OUTSL = ide_outsl; hwif->INB = ide_inb; - hwif->INW = ide_inw; - hwif->INSW = ide_insw; - hwif->INSL = ide_insl; } /* @@ -99,21 +63,6 @@ static u8 ide_mm_inb (unsigned long port) return (u8) readb((void __iomem *) port); } -static u16 ide_mm_inw (unsigned long port) -{ - return (u16) readw((void __iomem *) port); -} - -static void ide_mm_insw (unsigned long port, void *addr, u32 count) -{ - __ide_mm_insw((void __iomem *) port, addr, count); -} - -static void ide_mm_insl (unsigned long port, void *addr, u32 count) -{ - __ide_mm_insl((void __iomem *) port, addr, count); -} - static void ide_mm_outb (u8 value, unsigned long port) { writeb(value, (void __iomem *) port); @@ -124,34 +73,13 @@ static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port) writeb(value, (void __iomem *) port); } -static void ide_mm_outw (u16 value, unsigned long port) -{ - writew(value, (void __iomem *) port); -} - -static void ide_mm_outsw (unsigned long port, void *addr, u32 count) -{ - __ide_mm_outsw((void __iomem *) port, addr, count); -} - -static void ide_mm_outsl (unsigned long port, void *addr, u32 count) -{ - __ide_mm_outsl((void __iomem *) port, addr, count); -} - void default_hwif_mmiops (ide_hwif_t *hwif) { hwif->OUTB = ide_mm_outb; /* Most systems will need to override OUTBSYNC, alas however this one is controller specific! */ hwif->OUTBSYNC = ide_mm_outbsync; - hwif->OUTW = ide_mm_outw; - hwif->OUTSW = ide_mm_outsw; - hwif->OUTSL = ide_mm_outsl; hwif->INB = ide_mm_inb; - hwif->INW = ide_mm_inw; - hwif->INSW = ide_mm_insw; - hwif->INSL = ide_mm_insl; } EXPORT_SYMBOL(default_hwif_mmiops); @@ -175,6 +103,123 @@ void SELECT_MASK (ide_drive_t *drive, int mask) port_ops->maskproc(drive, mask); } +static void ide_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + void (*tf_outb)(u8 addr, unsigned long port); + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (mmio) + tf_outb = ide_mm_outb; + else + tf_outb = ide_outb; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + ide_set_irq(drive, 1); + + if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0) + SELECT_MASK(drive, 0); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) { + u16 data = (tf->hob_data << 8) | tf->data; + + if (mmio) + writew(data, (void __iomem *)io_ports->data_addr); + else + outw(data, io_ports->data_addr); + } + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + tf_outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + tf_outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + tf_outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + tf_outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + tf_outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + tf_outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + tf_outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + tf_outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + tf_outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + tf_outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + tf_outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void ide_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + void (*tf_outb)(u8 addr, unsigned long port); + u8 (*tf_inb)(unsigned long port); + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + if (mmio) { + tf_outb = ide_mm_outb; + tf_inb = ide_mm_inb; + } else { + tf_outb = ide_outb; + tf_inb = ide_inb; + } + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data; + + if (mmio) + data = readw((void __iomem *)io_ports->data_addr); + else + data = inw(io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + tf_outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = tf_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = tf_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = tf_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = tf_inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = tf_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + tf_outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = tf_inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = tf_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = tf_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = tf_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = tf_inb(io_ports->lbah_addr); + } +} + /* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data. We call this @@ -182,109 +227,112 @@ void SELECT_MASK (ide_drive_t *drive, int mask) * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */ -static void ata_vlb_sync(ide_drive_t *drive, unsigned long port) +static void ata_vlb_sync(unsigned long port) { - (void) HWIF(drive)->INB(port); - (void) HWIF(drive)->INB(port); - (void) HWIF(drive)->INB(port); + (void)inb(port); + (void)inb(port); + (void)inb(port); } /* * This is used for most PIO data transfers *from* the IDE interface + * + * These routines will round up any request for an odd number of bytes, + * so if an odd len is specified, be sure that there's at least one + * extra byte allocated for the buffer. */ -static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount) +static void ata_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) { ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long data_addr = io_ports->data_addr; u8 io_32bit = drive->io_32bit; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + len++; if (io_32bit) { - if (io_32bit & 2) { - unsigned long flags; + unsigned long uninitialized_var(flags); + if ((io_32bit & 2) && !mmio) { local_irq_save(flags); - ata_vlb_sync(drive, io_ports->nsect_addr); - hwif->INSL(io_ports->data_addr, buffer, wcount); + ata_vlb_sync(io_ports->nsect_addr); + } + + if (mmio) + __ide_mm_insl((void __iomem *)data_addr, buf, len / 4); + else + insl(data_addr, buf, len / 4); + + if ((io_32bit & 2) && !mmio) local_irq_restore(flags); - } else - hwif->INSL(io_ports->data_addr, buffer, wcount); - } else - hwif->INSW(io_ports->data_addr, buffer, wcount << 1); + + if ((len & 3) >= 2) { + if (mmio) + __ide_mm_insw((void __iomem *)data_addr, + (u8 *)buf + (len & ~3), 1); + else + insw(data_addr, (u8 *)buf + (len & ~3), 1); + } + } else { + if (mmio) + __ide_mm_insw((void __iomem *)data_addr, buf, len / 2); + else + insw(data_addr, buf, len / 2); + } } /* * This is used for most PIO data transfers *to* the IDE interface */ -static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount) +static void ata_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) { ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long data_addr = io_ports->data_addr; u8 io_32bit = drive->io_32bit; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; if (io_32bit) { - if (io_32bit & 2) { - unsigned long flags; + unsigned long uninitialized_var(flags); + if ((io_32bit & 2) && !mmio) { local_irq_save(flags); - ata_vlb_sync(drive, io_ports->nsect_addr); - hwif->OUTSL(io_ports->data_addr, buffer, wcount); - local_irq_restore(flags); - } else - hwif->OUTSL(io_ports->data_addr, buffer, wcount); - } else - hwif->OUTSW(io_ports->data_addr, buffer, wcount << 1); -} - -/* - * The following routines are mainly used by the ATAPI drivers. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ - -static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) -{ - ide_hwif_t *hwif = HWIF(drive); + ata_vlb_sync(io_ports->nsect_addr); + } - ++bytecount; -#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) - if (MACH_IS_ATARI || MACH_IS_Q40) { - /* Atari has a byte-swapped IDE interface */ - insw_swapw(hwif->io_ports.data_addr, buffer, bytecount / 2); - return; - } -#endif /* CONFIG_ATARI || CONFIG_Q40 */ - hwif->ata_input_data(drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - hwif->INSW(hwif->io_ports.data_addr, - (u8 *)buffer + (bytecount & ~0x03), 1); -} + if (mmio) + __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4); + else + outsl(data_addr, buf, len / 4); -static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) -{ - ide_hwif_t *hwif = HWIF(drive); + if ((io_32bit & 2) && !mmio) + local_irq_restore(flags); - ++bytecount; -#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) - if (MACH_IS_ATARI || MACH_IS_Q40) { - /* Atari has a byte-swapped IDE interface */ - outsw_swapw(hwif->io_ports.data_addr, buffer, bytecount / 2); - return; + if ((len & 3) >= 2) { + if (mmio) + __ide_mm_outsw((void __iomem *)data_addr, + (u8 *)buf + (len & ~3), 1); + else + outsw(data_addr, (u8 *)buf + (len & ~3), 1); + } + } else { + if (mmio) + __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2); + else + outsw(data_addr, buf, len / 2); } -#endif /* CONFIG_ATARI || CONFIG_Q40 */ - hwif->ata_output_data(drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - hwif->OUTSW(hwif->io_ports.data_addr, - (u8 *)buffer + (bytecount & ~0x03), 1); } void default_hwif_transport(ide_hwif_t *hwif) { - hwif->ata_input_data = ata_input_data; - hwif->ata_output_data = ata_output_data; - hwif->atapi_input_bytes = atapi_input_bytes; - hwif->atapi_output_bytes = atapi_output_bytes; + hwif->tf_load = ide_tf_load; + hwif->tf_read = ide_tf_read; + + hwif->input_data = ata_input_data; + hwif->output_data = ata_output_data; } void ide_fix_driveid (struct hd_driveid *id) @@ -577,6 +625,8 @@ static const struct drive_list_entry ivb_list[] = { { "TSSTcorp CDDVDW SH-S202J" , "SB01" }, { "TSSTcorp CDDVDW SH-S202N" , "SB00" }, { "TSSTcorp CDDVDW SH-S202N" , "SB01" }, + { "TSSTcorp CDDVDW SH-S202H" , "SB00" }, + { "TSSTcorp CDDVDW SH-S202H" , "SB01" }, { NULL , NULL } }; @@ -641,7 +691,7 @@ int ide_driveid_update(ide_drive_t *drive) SELECT_MASK(drive, 1); ide_set_irq(drive, 1); msleep(50); - hwif->OUTB(WIN_IDENTIFY, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, WIN_IDENTIFY, hwif->io_ports.command_addr); timeout = jiffies + WAIT_WORSTCASE; do { if (time_after(jiffies, timeout)) { @@ -668,7 +718,7 @@ int ide_driveid_update(ide_drive_t *drive) local_irq_restore(flags); return 0; } - hwif->ata_input_data(drive, id, SECTOR_WORDS); + hwif->input_data(drive, NULL, id, SECTOR_SIZE); (void)ide_read_status(drive); /* clear drive IRQ */ local_irq_enable(); local_irq_restore(flags); @@ -849,9 +899,19 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, ndelay(400); spin_unlock_irqrestore(&ide_lock, flags); } - EXPORT_SYMBOL(ide_execute_command); +void ide_execute_pkt_cmd(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned long flags; + + spin_lock_irqsave(&ide_lock, flags); + hwif->OUTBSYNC(drive, WIN_PACKETCMD, hwif->io_ports.command_addr); + ndelay(400); + spin_unlock_irqrestore(&ide_lock, flags); +} +EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd); /* needed below */ static ide_startstop_t do_reset1 (ide_drive_t *, int); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 6f04ea3e93a8..47af80df6872 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -487,7 +487,7 @@ static void ide_dump_sector(ide_drive_t *drive) else task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE; - ide_tf_read(drive, &task); + drive->hwif->tf_read(drive, &task); if (lba48 || (tf->device & ATA_LBA)) printk(", LBAsect=%llu", diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 862f02603f9b..591deda3f86a 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -124,7 +124,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) id = drive->id; /* read 512 bytes of id info */ - hwif->ata_input_data(drive, id, SECTOR_WORDS); + hwif->input_data(drive, NULL, id, SECTOR_SIZE); drive->id_read = 1; local_irq_enable(); @@ -293,7 +293,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) hwif->OUTB(0, io_ports->feature_addr); /* ask drive for ID */ - hwif->OUTB(cmd, io_ports->command_addr); + hwif->OUTBSYNC(drive, cmd, io_ports->command_addr); timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; @@ -480,7 +480,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) msleep(50); hwif->OUTB(drive->select.all, io_ports->device_addr); msleep(50); - hwif->OUTB(WIN_SRST, io_ports->command_addr); + hwif->OUTBSYNC(drive, WIN_SRST, io_ports->command_addr); (void)ide_busy_sleep(hwif); rc = try_to_identify(drive, cmd); } @@ -516,7 +516,7 @@ static void enable_nest (ide_drive_t *drive) printk("%s: enabling %s -- ", hwif->name, drive->id->model); SELECT_DRIVE(drive); msleep(50); - hwif->OUTB(EXABYTE_ENABLE_NEST, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, EXABYTE_ENABLE_NEST, hwif->io_ports.command_addr); if (ide_busy_sleep(hwif)) { printk(KERN_CONT "failed (timeout)\n"); @@ -1347,7 +1347,8 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS)) hwif->irq = port ? 15 : 14; - hwif->host_flags = d->host_flags; + /* ->host_flags may be set by ->init_iops (or even earlier...) */ + hwif->host_flags |= d->host_flags; hwif->pio_mask = d->pio_mask; /* ->set_pio_mode for DTC2278 is currently limited to port 0 */ diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 7b2f3815a838..8d6ad812a014 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -822,6 +822,7 @@ static int ide_drivers_open(struct inode *inode, struct file *file) } static const struct file_operations ide_drivers_operations = { + .owner = THIS_MODULE, .open = ide_drivers_open, .read = seq_read, .llseek = seq_lseek, @@ -830,16 +831,12 @@ static const struct file_operations ide_drivers_operations = { void proc_ide_create(void) { - struct proc_dir_entry *entry; - proc_ide_root = proc_mkdir("ide", NULL); if (!proc_ide_root) return; - entry = create_proc_entry("drivers", 0, proc_ide_root); - if (entry) - entry->proc_fops = &ide_drivers_operations; + proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations); } void proc_ide_destroy(void) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 29870c415110..1e1f26331a24 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -395,13 +395,13 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bh == NULL) { printk(KERN_ERR "ide-tape: bh == NULL in " "idetape_input_buffers\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); return; } count = min( (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount); - HWIF(drive)->atapi_input_bytes(drive, bh->b_data + + drive->hwif->input_data(drive, NULL, bh->b_data + atomic_read(&bh->b_count), count); bcount -= count; atomic_add(count, &bh->b_count); @@ -427,7 +427,7 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, return; } count = min((unsigned int)pc->b_count, (unsigned int)bcount); - HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count); + drive->hwif->output_data(drive, NULL, pc->b_data, count); bcount -= count; pc->b_data += count; pc->b_count -= count; @@ -662,7 +662,7 @@ static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc) static void idetape_init_rq(struct request *rq, u8 cmd) { - memset(rq, 0, sizeof(*rq)); + blk_rq_init(NULL, rq); rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[0] = cmd; } @@ -871,7 +871,7 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) printk(KERN_ERR "ide-tape: The tape wants to " "send us more data than expected " "- discarding data\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; @@ -880,16 +880,16 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) "data than expected - allowing transfer\n"); } iobuf = &idetape_input_buffers; - xferfunc = hwif->atapi_input_bytes; + xferfunc = hwif->input_data; } else { iobuf = &idetape_output_buffers; - xferfunc = hwif->atapi_output_bytes; + xferfunc = hwif->output_data; } if (pc->bh) iobuf(drive, pc, bcount); else - xferfunc(drive, pc->cur_pos, bcount); + xferfunc(drive, NULL, pc->cur_pos, bcount); /* Update the current position */ pc->xferred += bcount; @@ -979,7 +979,8 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) hwif->dma_ops->dma_start(drive); #endif /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, pc->c, 12); + hwif->output_data(drive, NULL, pc->c, 12); + return ide_started; } @@ -1055,7 +1056,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, IDETAPE_WAIT_CMD, NULL); return ide_started; } else { - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); + ide_execute_pkt_cmd(drive); return idetape_transfer_pc(drive); } } diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 9f9ad9fb6b89..0c908ca3ff79 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -33,60 +33,18 @@ #include <asm/uaccess.h> #include <asm/io.h> -void ide_tf_load(ide_drive_t *drive, ide_task_t *task) +void ide_tf_dump(const char *s, struct ide_taskfile *tf) { - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_taskfile *tf = &task->tf; - u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; - - if (task->tf_flags & IDE_TFLAG_FLAGGED) - HIHI = 0xFF; - #ifdef DEBUG printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n", - drive->name, tf->feature, tf->nsect, tf->lbal, + s, tf->feature, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->device, tf->command); printk("%s: hob: nsect 0x%02x lbal 0x%02x " "lbam 0x%02x lbah 0x%02x\n", - drive->name, tf->hob_nsect, tf->hob_lbal, + s, tf->hob_nsect, tf->hob_lbal, tf->hob_lbam, tf->hob_lbah); #endif - - ide_set_irq(drive, 1); - - if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0) - SELECT_MASK(drive, 0); - - if (task->tf_flags & IDE_TFLAG_OUT_DATA) - hwif->OUTW((tf->hob_data << 8) | tf->data, io_ports->data_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) - hwif->OUTB(tf->hob_feature, io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) - hwif->OUTB(tf->hob_nsect, io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) - hwif->OUTB(tf->hob_lbal, io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) - hwif->OUTB(tf->hob_lbam, io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) - hwif->OUTB(tf->hob_lbah, io_ports->lbah_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) - hwif->OUTB(tf->feature, io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_OUT_NSECT) - hwif->OUTB(tf->nsect, io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAL) - hwif->OUTB(tf->lbal, io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAM) - hwif->OUTB(tf->lbam, io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAH) - hwif->OUTB(tf->lbah, io_ports->lbah_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) - hwif->OUTB((tf->device & HIHI) | drive->select.all, - io_ports->device_addr); } int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) @@ -149,8 +107,10 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) if (task->tf_flags & IDE_TFLAG_FLAGGED) task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS; - if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) - ide_tf_load(drive, task); + if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { + ide_tf_dump(drive->name, tf); + hwif->tf_load(drive, task); + } switch (task->data_phase) { case TASKFILE_MULTI_OUT: @@ -283,7 +243,8 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) return stat; } -static void ide_pio_sector(ide_drive_t *drive, unsigned int write) +static void ide_pio_sector(ide_drive_t *drive, struct request *rq, + unsigned int write) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; @@ -323,9 +284,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) /* do the actual data transfer */ if (write) - hwif->ata_output_data(drive, buf, SECTOR_WORDS); + hwif->output_data(drive, rq, buf, SECTOR_SIZE); else - hwif->ata_input_data(drive, buf, SECTOR_WORDS); + hwif->input_data(drive, rq, buf, SECTOR_SIZE); kunmap_atomic(buf, KM_BIO_SRC_IRQ); #ifdef CONFIG_HIGHMEM @@ -333,13 +294,14 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) #endif } -static void ide_pio_multi(ide_drive_t *drive, unsigned int write) +static void ide_pio_multi(ide_drive_t *drive, struct request *rq, + unsigned int write) { unsigned int nsect; nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count); while (nsect--) - ide_pio_sector(drive, write); + ide_pio_sector(drive, rq, write); } static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, @@ -362,10 +324,10 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, switch (drive->hwif->data_phase) { case TASKFILE_MULTI_IN: case TASKFILE_MULTI_OUT: - ide_pio_multi(drive, write); + ide_pio_multi(drive, rq, write); break; default: - ide_pio_sector(drive, write); + ide_pio_sector(drive, rq, write); break; } @@ -532,8 +494,7 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) { struct request rq; - memset(&rq, 0, sizeof(rq)); - rq.ref_count = 1; + blk_rq_init(NULL, &rq); rq.cmd_type = REQ_TYPE_ATA_TASKFILE; rq.buffer = buf; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 999584c03d97..c758dcb13b14 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -564,7 +564,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) if (!(drive->dn % 2)) ide_acpi_get_timing(hwif); - memset(&rq, 0, sizeof(rq)); + blk_rq_init(NULL, &rq); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_SUSPEND; @@ -602,7 +602,7 @@ static int generic_ide_resume(struct device *dev) ide_acpi_exec_tfs(drive); - memset(&rq, 0, sizeof(rq)); + blk_rq_init(NULL, &rq); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_RESUME; diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index 56cdaa0eeea5..83555ca513b5 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -44,6 +44,28 @@ int falconide_intr_lock; EXPORT_SYMBOL(falconide_intr_lock); +static void falconide_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return insw(data_addr, buf, (len + 1) / 2); + + insw_swapw(data_addr, buf, (len + 1) / 2); +} + +static void falconide_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return outsw(data_adr, buf, (len + 1) / 2); + + outsw_swapw(data_addr, buf, (len + 1) / 2); +} + static void __init falconide_setup_ports(hw_regs_t *hw) { int i; @@ -90,6 +112,10 @@ static int __init falconide_init(void) ide_init_port_data(hwif, index); ide_init_port_hw(hwif, &hw); + /* Atari has a byte-swapped IDE interface */ + hwif->input_data = falconide_input_data; + hwif->output_data = falconide_output_data; + ide_get_lock(NULL, NULL); ide_device_add(idx, NULL); ide_release_lock(); diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index 8279dc7ca4c0..d3bc3f24e05d 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -101,8 +101,10 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) ide_init_port_hw(hwif, &hw); - if (mmio) + if (mmio) { + hwif->host_flags = IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); + } idx[0] = hwif->index; diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index a3573d40b4b7..6f535d00e638 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -36,23 +36,6 @@ static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = { PCIDE_BASE6 */ }; - - /* - * Offsets from one of the above bases - */ - -/* used to do addr translation here but it is easier to do in setup ports */ -/*#define IDE_OFF_B(x) ((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/ - -#define IDE_OFF_B(x) ((unsigned long)((IDE_##x##_OFFSET))) -#define IDE_OFF_W(x) ((unsigned long)((IDE_##x##_OFFSET))) - -static const int pcide_offsets[IDE_NR_PORTS] = { - IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR), - IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS), - 518/*IDE_OFF(CMD)*/ -}; - static int q40ide_default_irq(unsigned long base) { switch (base) { @@ -68,29 +51,48 @@ static int q40ide_default_irq(unsigned long base) /* * Addresses are pretranslated for Q40 ISA access. */ -void q40_ide_setup_ports ( hw_regs_t *hw, - unsigned long base, int *offsets, - unsigned long ctrl, unsigned long intr, +static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base, ide_ack_intr_t *ack_intr, int irq) { - int i; - memset(hw, 0, sizeof(hw_regs_t)); - for (i = 0; i < IDE_NR_PORTS; i++) { - /* BIG FAT WARNING: - assumption: only DATA port is ever used in 16 bit mode */ - if (i == 0) - hw->io_ports_array[i] = Q40_ISA_IO_W(base + offsets[i]); - else - hw->io_ports_array[i] = Q40_ISA_IO_B(base + offsets[i]); - } + /* BIG FAT WARNING: + assumption: only DATA port is ever used in 16 bit mode */ + hw->io_ports.data_addr = Q40_ISA_IO_W(base); + hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1); + hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2); + hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3); + hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4); + hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5); + hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6); + hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7); + hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206); hw->irq = irq; hw->ack_intr = ack_intr; } +static void q40ide_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return insw(data_addr, buf, (len + 1) / 2); + insw_swapw(data_addr, buf, (len + 1) / 2); +} + +static void q40ide_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return outsw(data_addr, buf, (len + 1) / 2); + + outsw_swapw(data_addr, buf, (len + 1) / 2); +} /* * the static array is needed to have the name reported in /proc/ioports, @@ -131,9 +133,8 @@ static int __init q40ide_init(void) release_region(pcide_bases[i], 8); continue; } - q40_ide_setup_ports(&hw,(unsigned long) pcide_bases[i], (int *)pcide_offsets, - pcide_bases[i]+0x206, - 0, NULL, + q40_ide_setup_ports(&hw, pcide_bases[i], + NULL, // m68kide_iops, q40ide_default_irq(pcide_bases[i])); @@ -142,6 +143,10 @@ static int __init q40ide_init(void) ide_init_port_data(hwif, hwif->index); ide_init_port_hw(hwif, &hw); + /* Q40 has a byte-swapped IDE interface */ + hwif->input_data = q40ide_input_data; + hwif->output_data = q40ide_output_data; + idx[i] = hwif->index; } } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 296b9c674bae..1a6c27b32498 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -48,8 +48,6 @@ static _auide_hwif auide_hwif; -static int auide_ddma_init(_auide_hwif *auide); - #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) void auide_insw(unsigned long port, void *addr, u32 count) @@ -88,6 +86,17 @@ void auide_outsw(unsigned long port, void *addr, u32 count) ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); } +static void au1xxx_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + +static void au1xxx_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} #endif static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio) @@ -359,7 +368,7 @@ static void auide_ddma_rx_callback(int irq, void *param) static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags) { dev->dev_id = dev_id; - dev->dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + dev->dev_physaddr = (u32)IDE_PHYS_ADDR; dev->dev_intlevel = 0; dev->dev_intpolarity = 0; dev->dev_tsize = tsize; @@ -397,7 +406,7 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d) dbdev_tab_t source_dev_tab, target_dev_tab; u32 dev_id, tsize, devwidth, flags; - dev_id = AU1XXX_ATA_DDMA_REQ; + dev_id = IDE_DDMA_REQ; tsize = 8; /* 1 */ devwidth = 32; /* 16 */ @@ -506,10 +515,10 @@ static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif) /* FIXME? */ for (i = 0; i < 8; i++) - *ata_regs++ = ahwif->regbase + (i << AU1XXX_ATA_REG_OFFSET); + *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT); /* set the Alternative Status register */ - *ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET); + *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT); } static const struct ide_port_ops au1xxx_port_ops = { @@ -598,8 +607,8 @@ static int au_ide_probe(struct device *dev) */ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - hwif->INSW = auide_insw; - hwif->OUTSW = auide_outsw; + hwif->input_data = au1xxx_input_data; + hwif->output_data = au1xxx_output_data; #endif hwif->select_data = 0; /* no chipset-specific code */ hwif->config_data = 0; /* no chipset-specific code */ diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 68947626e4aa..712d17bdd470 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c @@ -109,6 +109,7 @@ static int __devinit swarm_ide_probe(struct device *dev) base = ioremap(offset, size); /* Setup MMIO ops. */ + hwif->host_flags = IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); hwif->chipset = ide_generic; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index b36a22b8c213..c1922f9cfe80 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -412,14 +412,14 @@ static u8 __devinit ali_cable_detect(ide_hwif_t *hwif) return cbl; } -#ifndef CONFIG_SPARC64 +#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) /** * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff * @hwif: interface to configure * * Obtain the IRQ tables for an ALi based IDE solution on the PC * class platforms. This part of the code isn't applicable to the - * Sparc systems + * Sparc and PowerPC systems. */ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) @@ -463,7 +463,9 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) hwif->irq = irq; } } -#endif +#else +#define init_hwif_ali15x3 NULL +#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */ /** * init_dma_ali15x3 - set up DMA on ALi15x3 @@ -517,9 +519,7 @@ static const struct ide_dma_ops ali_dma_ops = { static const struct ide_port_info ali15x3_chipset __devinitdata = { .name = "ALI15X3", .init_chipset = init_chipset_ali15x3, -#ifndef CONFIG_SPARC64 .init_hwif = init_hwif_ali15x3, -#endif .init_dma = init_dma_ali15x3, .port_ops = &ali_port_ops, .pio_mask = ATA_PIO5, diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index c13e299077ec..fec4955f449b 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -63,6 +63,48 @@ static u8 superio_ide_inb (unsigned long port) return inb(port); } +static void superio_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = inw(io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = superio_ide_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = inb(io_ports->lbah_addr); + } +} + static void __devinit superio_ide_init_iops (struct hwif_s *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); @@ -80,6 +122,8 @@ static void __devinit superio_ide_init_iops (struct hwif_s *hwif) tmp = superio_ide_inb(superio_ide_dma_status[port]); outb(tmp | 0x66, superio_ide_dma_status[port]); + hwif->tf_read = superio_tf_read; + /* We need to override inb to workaround a SuperIO errata */ hwif->INB = superio_ide_inb; } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index ec9bd7b352fc..070df8ab3b21 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -83,8 +83,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) { u8 value; - outb(index, hwif->dma_vendor1); - value = inb(hwif->dma_vendor3); + outb(index, hwif->dma_base + 1); + value = inb(hwif->dma_base + 3); DBG("index[%02X] value[%02X]\n", index, value); return value; @@ -97,8 +97,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) */ static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) { - outb(index, hwif->dma_vendor1); - outb(value, hwif->dma_vendor3); + outb(index, hwif->dma_base + 1); + outb(value, hwif->dma_base + 3); DBG("index[%02X] value[%02X]\n", index, value); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 21c5dd23f928..f04738d14a6f 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -250,6 +250,7 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */ + { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ /* end marker */ { 0, } }; diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index ad7cdf9060ca..910fb00deb71 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -126,12 +126,6 @@ static u8 scc_ide_inb(unsigned long port) return (u8)data; } -static u16 scc_ide_inw(unsigned long port) -{ - u32 data = in_be32((void*)port); - return (u16)data; -} - static void scc_ide_insw(unsigned long port, void *addr, u32 count) { u16 *ptr = (u16 *)addr; @@ -154,11 +148,6 @@ static void scc_ide_outb(u8 addr, unsigned long port) out_be32((void*)port, addr); } -static void scc_ide_outw(u16 addr, unsigned long port) -{ - out_be32((void*)port, addr); -} - static void scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port) { @@ -271,6 +260,20 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) out_be32((void __iomem *)udenvt_port, reg); } +static void scc_dma_host_set(ide_drive_t *drive, int on) +{ + ide_hwif_t *hwif = drive->hwif; + u8 unit = (drive->select.b.unit & 0x01); + u8 dma_stat = scc_ide_inb(hwif->dma_status); + + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + scc_ide_outb(dma_stat, hwif->dma_status); +} + /** * scc_ide_dma_setup - begin a DMA phase * @drive: target device @@ -301,7 +304,7 @@ static int scc_dma_setup(ide_drive_t *drive) } /* PRD table */ - out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma); + out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma); /* specify r/w */ out_be32((void __iomem *)hwif->dma_command, reading); @@ -315,13 +318,45 @@ static int scc_dma_setup(ide_drive_t *drive) return 0; } +static void scc_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_cmd = scc_ide_inb(hwif->dma_command); + + /* start DMA */ + scc_ide_outb(dma_cmd | 1, hwif->dma_command); + hwif->dma = 1; + wmb(); +} + +static int __scc_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat, dma_cmd; + + drive->waiting_for_dma = 0; + /* get DMA command mode */ + dma_cmd = scc_ide_inb(hwif->dma_command); + /* stop DMA */ + scc_ide_outb(dma_cmd & ~1, hwif->dma_command); + /* get DMA status */ + dma_stat = scc_ide_inb(hwif->dma_status); + /* clear the INTR & ERROR bits */ + scc_ide_outb(dma_stat | 6, hwif->dma_status); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + hwif->dma = 0; + wmb(); + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; +} /** * scc_dma_end - Stop DMA * @drive: IDE drive * * Check and clear INT Status register. - * Then call __ide_dma_end(). + * Then call __scc_dma_end(). */ static int scc_dma_end(ide_drive_t *drive) @@ -425,7 +460,7 @@ static int scc_dma_end(ide_drive_t *drive) break; } - dma_stat = __ide_dma_end(drive); + dma_stat = __scc_dma_end(drive); if (data_loss) dma_stat |= 2; /* emulate DMA error (to retry command) */ return dma_stat; @@ -618,6 +653,122 @@ static int __devinit init_setup_scc(struct pci_dev *dev, return rc; } +static void scc_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + ide_set_irq(drive, 1); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) + out_be32((void *)io_ports->data_addr, + (tf->hob_data << 8) | tf->data); + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + scc_ide_outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + scc_ide_outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + scc_ide_outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + scc_ide_outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + scc_ide_outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + scc_ide_outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + scc_ide_outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + scc_ide_outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + scc_ide_outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + scc_ide_outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + scc_ide_outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void scc_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = (u16)in_be32((void *)io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + scc_ide_outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = scc_ide_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = scc_ide_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = scc_ide_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = scc_ide_inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = scc_ide_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + scc_ide_outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = scc_ide_inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr); + } +} + +static void scc_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_insl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_insw(data_addr, buf, len / 2); +} + +static void scc_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_outsl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_outsw(data_addr, buf, len / 2); +} + /** * init_mmio_iops_scc - set up the iops for MMIO * @hwif: interface to set up @@ -632,15 +783,15 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) ide_set_hwifdata(hwif, ports); + hwif->tf_load = scc_tf_load; + hwif->tf_read = scc_tf_read; + + hwif->input_data = scc_input_data; + hwif->output_data = scc_output_data; + hwif->INB = scc_ide_inb; - hwif->INW = scc_ide_inw; - hwif->INSW = scc_ide_insw; - hwif->INSL = scc_ide_insl; hwif->OUTB = scc_ide_outb; hwif->OUTBSYNC = scc_ide_outbsync; - hwif->OUTW = scc_ide_outw; - hwif->OUTSW = scc_ide_outsw; - hwif->OUTSL = scc_ide_outsl; hwif->dma_base = dma_base; hwif->config_data = ports->ctl; @@ -687,7 +838,6 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->dma_command = hwif->dma_base; hwif->dma_status = hwif->dma_base + 0x04; - hwif->dma_prdtable = hwif->dma_base + 0x08; /* PTERADD */ out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); @@ -706,10 +856,10 @@ static const struct ide_port_ops scc_port_ops = { }; static const struct ide_dma_ops scc_dma_ops = { - .dma_host_set = ide_dma_host_set, + .dma_host_set = scc_dma_host_set, .dma_setup = scc_dma_setup, .dma_exec_cmd = ide_dma_exec_cmd, - .dma_start = ide_dma_start, + .dma_start = scc_dma_start, .dma_end = scc_dma_end, .dma_test_irq = scc_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 63e28f4e6d3b..16a0bce17d69 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -573,6 +573,7 @@ static const struct ide_port_info sgiioc4_port_info __devinitdata = { .init_dma = ide_dma_sgiioc4, .port_ops = &sgiioc4_port_ops, .dma_ops = &sgiioc4_dma_ops, + .host_flags = IDE_HFLAG_MMIO, .mwdma_mask = ATA_MWDMA2_ONLY, }; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index c2040a017f47..0006b9e58567 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,8 +1,8 @@ /* * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> - * Copyright (C) 2007 MontaVista Software, Inc. - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * Copyright (C) 2007-2008 MontaVista Software, Inc. + * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public License * @@ -17,10 +17,10 @@ * * FAQ Items: * If you are using Marvell SATA-IDE adapters with Maxtor drives - * ensure the system is set up for ATA100/UDMA5 not UDMA6. + * ensure the system is set up for ATA100/UDMA5, not UDMA6. * * If you are using WD drives with SATA bridges you must set the - * drive to "Single". "Master" will hang + * drive to "Single". "Master" will hang. * * If you have strange problems with nVidia chipset systems please * see the SI support documentation and update your system BIOS @@ -42,25 +42,24 @@ #include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> - -#include <asm/io.h> +#include <linux/io.h> /** * pdev_is_sata - check if device is SATA * @pdev: PCI device to check - * + * * Returns true if this is a SATA controller */ - + static int pdev_is_sata(struct pci_dev *pdev) { #ifdef CONFIG_BLK_DEV_IDE_SATA - switch(pdev->device) { - case PCI_DEVICE_ID_SII_3112: - case PCI_DEVICE_ID_SII_1210SA: - return 1; - case PCI_DEVICE_ID_SII_680: - return 0; + switch (pdev->device) { + case PCI_DEVICE_ID_SII_3112: + case PCI_DEVICE_ID_SII_1210SA: + return 1; + case PCI_DEVICE_ID_SII_680: + return 0; } BUG(); #endif @@ -70,10 +69,10 @@ static int pdev_is_sata(struct pci_dev *pdev) /** * is_sata - check if hwif is SATA * @hwif: interface to check - * + * * Returns true if this is a SATA controller */ - + static inline int is_sata(ide_hwif_t *hwif) { return pdev_is_sata(to_pci_dev(hwif->dev)); @@ -86,21 +85,22 @@ static inline int is_sata(ide_hwif_t *hwif) * * Turn a config register offset into the right address in either * PCI space or MMIO space to access the control register in question - * Thankfully this is a configuration operation so isnt performance - * criticial. + * Thankfully this is a configuration operation, so isn't performance + * critical. */ - + static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) { unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; - if(hwif->mmio) - base += (hwif->channel << 6); + if (hwif->mmio) + base += hwif->channel << 6; else - base += (hwif->channel << 4); + base += hwif->channel << 4; return base; } - + /** * siimage_seldev - return register base * @hwif: interface @@ -110,20 +110,69 @@ static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) * PCI space or MMIO space to access the control register in question * including accounting for the unit shift. */ - + static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) { ide_hwif_t *hwif = HWIF(drive); - unsigned long base = (unsigned long)hwif->hwif_data; + unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; - if(hwif->mmio) - base += (hwif->channel << 6); + if (hwif->mmio) + base += hwif->channel << 6; else - base += (hwif->channel << 4); + base += hwif->channel << 4; base |= drive->select.b.unit << drive->select.b.unit; return base; } +static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr) +{ + u8 tmp = 0; + + if (pci_get_drvdata(dev)) + tmp = readb((void __iomem *)addr); + else + pci_read_config_byte(dev, addr, &tmp); + + return tmp; +} + +static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr) +{ + u16 tmp = 0; + + if (pci_get_drvdata(dev)) + tmp = readw((void __iomem *)addr); + else + pci_read_config_word(dev, addr, &tmp); + + return tmp; +} + +static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr) +{ + if (pci_get_drvdata(dev)) + writeb(val, (void __iomem *)addr); + else + pci_write_config_byte(dev, addr, val); +} + +static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr) +{ + if (pci_get_drvdata(dev)) + writew(val, (void __iomem *)addr); + else + pci_write_config_word(dev, addr, val); +} + +static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr) +{ + if (pci_get_drvdata(dev)) + writel(val, (void __iomem *)addr); + else + pci_write_config_dword(dev, addr, val); +} + /** * sil_udma_filter - compute UDMA mask * @drive: IDE device @@ -136,24 +185,26 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) static u8 sil_pata_udma_filter(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = (unsigned long) hwif->hwif_data; - u8 mask = 0, scsc = 0; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = (unsigned long)hwif->hwif_data; + u8 scsc, mask = 0; - if (hwif->mmio) - scsc = hwif->INB(base + 0x4A); - else - pci_read_config_byte(dev, 0x8A, &scsc); + scsc = sil_ioread8(dev, base + (hwif->mmio ? 0x4A : 0x8A)); - if ((scsc & 0x30) == 0x10) /* 133 */ + switch (scsc & 0x30) { + case 0x10: /* 133 */ mask = ATA_UDMA6; - else if ((scsc & 0x30) == 0x20) /* 2xPCI */ + break; + case 0x20: /* 2xPCI */ mask = ATA_UDMA6; - else if ((scsc & 0x30) == 0x00) /* 100 */ + break; + case 0x00: /* 100 */ mask = ATA_UDMA5; - else /* Disabled ? */ + break; + default: /* Disabled ? */ BUG(); + } return mask; } @@ -175,15 +226,16 @@ static u8 sil_sata_udma_filter(ide_drive_t *drive) static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) { - const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; - const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; + static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; + static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); ide_drive_t *pair = ide_get_paired_drive(drive); u32 speedt = 0; u16 speedp = 0; unsigned long addr = siimage_seldev(drive, 0x04); - unsigned long tfaddr = siimage_selreg(hwif, 0x02); + unsigned long tfaddr = siimage_selreg(hwif, 0x02); unsigned long base = (unsigned long)hwif->hwif_data; u8 tf_pio = pio; u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84) @@ -203,36 +255,20 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) speedp = data_speed[pio]; speedt = tf_speed[tf_pio]; - if (hwif->mmio) { - hwif->OUTW(speedp, addr); - hwif->OUTW(speedt, tfaddr); - /* Now set up IORDY */ - if (pio > 2) - hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); - else - hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); - - mode = hwif->INB(base + addr_mask); - mode &= ~(unit ? 0x30 : 0x03); - mode |= (unit ? 0x10 : 0x01); - hwif->OUTB(mode, base + addr_mask); - } else { - struct pci_dev *dev = to_pci_dev(hwif->dev); - - pci_write_config_word(dev, addr, speedp); - pci_write_config_word(dev, tfaddr, speedt); - pci_read_config_word(dev, tfaddr - 2, &speedp); - speedp &= ~0x200; - /* Set IORDY for mode 3 or 4 */ - if (pio > 2) - speedp |= 0x200; - pci_write_config_word(dev, tfaddr - 2, speedp); - - pci_read_config_byte(dev, addr_mask, &mode); - mode &= ~(unit ? 0x30 : 0x03); - mode |= (unit ? 0x10 : 0x01); - pci_write_config_byte(dev, addr_mask, mode); - } + sil_iowrite16(dev, speedp, addr); + sil_iowrite16(dev, speedt, tfaddr); + + /* now set up IORDY */ + speedp = sil_ioread16(dev, tfaddr - 2); + speedp &= ~0x200; + if (pio > 2) + speedp |= 0x200; + sil_iowrite16(dev, speedp, tfaddr - 2); + + mode = sil_ioread8(dev, base + addr_mask); + mode &= ~(unit ? 0x30 : 0x03); + mode |= unit ? 0x10 : 0x01; + sil_iowrite8(dev, mode, base + addr_mask); } /** @@ -245,59 +281,45 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) { - u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; - u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; - u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; + static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; + static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; + static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = to_pci_dev(hwif->dev); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; unsigned long base = (unsigned long)hwif->hwif_data; - u8 scsc = 0, addr_mask = ((hwif->channel) ? - ((hwif->mmio) ? 0xF4 : 0x84) : - ((hwif->mmio) ? 0xB4 : 0x80)); - + u8 scsc = 0, addr_mask = hwif->channel ? + (hwif->mmio ? 0xF4 : 0x84) : + (hwif->mmio ? 0xB4 : 0x80); unsigned long ma = siimage_seldev(drive, 0x08); unsigned long ua = siimage_seldev(drive, 0x0C); - if (hwif->mmio) { - scsc = hwif->INB(base + 0x4A); - mode = hwif->INB(base + addr_mask); - multi = hwif->INW(ma); - ultra = hwif->INW(ua); - } else { - pci_read_config_byte(dev, 0x8A, &scsc); - pci_read_config_byte(dev, addr_mask, &mode); - pci_read_config_word(dev, ma, &multi); - pci_read_config_word(dev, ua, &ultra); - } + scsc = sil_ioread8 (dev, base + (hwif->mmio ? 0x4A : 0x8A)); + mode = sil_ioread8 (dev, base + addr_mask); + multi = sil_ioread16(dev, ma); + ultra = sil_ioread16(dev, ua); - mode &= ~((unit) ? 0x30 : 0x03); + mode &= ~(unit ? 0x30 : 0x03); ultra &= ~0x3F; scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; scsc = is_sata(hwif) ? 1 : scsc; if (speed >= XFER_UDMA_0) { - multi = dma[2]; - ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] : - ultra5[speed - XFER_UDMA_0]); - mode |= (unit ? 0x30 : 0x03); + multi = dma[2]; + ultra |= scsc ? ultra6[speed - XFER_UDMA_0] : + ultra5[speed - XFER_UDMA_0]; + mode |= unit ? 0x30 : 0x03; } else { multi = dma[speed - XFER_MW_DMA_0]; - mode |= (unit ? 0x20 : 0x02); + mode |= unit ? 0x20 : 0x02; } - if (hwif->mmio) { - hwif->OUTB(mode, base + addr_mask); - hwif->OUTW(multi, ma); - hwif->OUTW(ultra, ua); - } else { - pci_write_config_byte(dev, addr_mask, mode); - pci_write_config_word(dev, ma, multi); - pci_write_config_word(dev, ua, ultra); - } + sil_iowrite8 (dev, mode, base + addr_mask); + sil_iowrite16(dev, multi, ma); + sil_iowrite16(dev, ultra, ua); } /* returns 1 if dma irq issued, 0 otherwise */ @@ -309,13 +331,14 @@ static int siimage_io_dma_test_irq(ide_drive_t *drive) unsigned long addr = siimage_selreg(hwif, 1); /* return 1 if INTR asserted */ - if ((hwif->INB(hwif->dma_status) & 4) == 4) + if (hwif->INB(hwif->dma_status) & 4) return 1; /* return 1 if Device INTR asserted */ pci_read_config_byte(dev, addr, &dma_altstat); if (dma_altstat & 8) - return 0; //return 1; + return 0; /* return 1; */ + return 0; } @@ -335,9 +358,9 @@ static int siimage_mmio_dma_test_irq(ide_drive_t *drive) = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; if (sata_error_addr) { - unsigned long base = (unsigned long)hwif->hwif_data; - u32 ext_stat = readl((void __iomem *)(base + 0x10)); - u8 watchdog = 0; + unsigned long base = (unsigned long)hwif->hwif_data; + u32 ext_stat = readl((void __iomem *)(base + 0x10)); + u8 watchdog = 0; if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { u32 sata_error = readl(sata_error_addr); @@ -346,25 +369,22 @@ static int siimage_mmio_dma_test_irq(ide_drive_t *drive) watchdog = (sata_error & 0x00680000) ? 1 : 0; printk(KERN_WARNING "%s: sata_error = 0x%08x, " "watchdog = %d, %s\n", - drive->name, sata_error, watchdog, - __func__); - - } else { + drive->name, sata_error, watchdog, __func__); + } else watchdog = (ext_stat & 0x8000) ? 1 : 0; - } - ext_stat >>= 16; + ext_stat >>= 16; if (!(ext_stat & 0x0404) && !watchdog) return 0; } /* return 1 if INTR asserted */ - if ((readb((void __iomem *)hwif->dma_status) & 0x04) == 0x04) + if (readb((void __iomem *)hwif->dma_status) & 0x04) return 1; /* return 1 if Device INTR asserted */ - if ((readb((void __iomem *)addr) & 8) == 8) - return 0; //return 1; + if (readb((void __iomem *)addr) & 8) + return 0; /* return 1; */ return 0; } @@ -423,63 +443,33 @@ static void sil_sata_pre_reset(ide_drive_t *drive) } /** - * proc_reports_siimage - add siimage controller to proc - * @dev: PCI device - * @clocking: SCSC value - * @name: controller name - * - * Report the clocking mode of the controller and add it to - * the /proc interface layer - */ - -static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name) -{ - if (!pdev_is_sata(dev)) { - printk(KERN_INFO "%s: BASE CLOCK ", name); - clocking &= 0x03; - switch (clocking) { - case 0x03: printk("DISABLED!\n"); break; - case 0x02: printk("== 2X PCI\n"); break; - case 0x01: printk("== 133\n"); break; - case 0x00: printk("== 100\n"); break; - } - } -} - -/** - * setup_mmio_siimage - switch an SI controller into MMIO + * setup_mmio_siimage - switch controller into MMIO mode * @dev: PCI device we are configuring * @name: device name * - * Attempt to put the device into mmio mode. There are some slight - * complications here with certain systems where the mmio bar isnt - * mapped so we have to be sure we can fall back to I/O. + * Attempt to put the device into MMIO mode. There are some slight + * complications here with certain systems where the MMIO BAR isn't + * mapped, so we have to be sure that we can fall back to I/O. */ - -static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) + +static unsigned int setup_mmio_siimage(struct pci_dev *dev, const char *name) { resource_size_t bar5 = pci_resource_start(dev, 5); unsigned long barsize = pci_resource_len(dev, 5); - u8 tmpbyte = 0; void __iomem *ioaddr; - u32 tmp, irq_mask; /* - * Drop back to PIO if we can't map the mmio. Some - * systems seem to get terminally confused in the PCI - * spaces. + * Drop back to PIO if we can't map the MMIO. Some systems + * seem to get terminally confused in the PCI spaces. */ - - if(!request_mem_region(bar5, barsize, name)) - { - printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n"); + if (!request_mem_region(bar5, barsize, name)) { + printk(KERN_WARNING "siimage: IDE controller MMIO ports not " + "available.\n"); return 0; } - - ioaddr = ioremap(bar5, barsize); - if (ioaddr == NULL) - { + ioaddr = ioremap(bar5, barsize); + if (ioaddr == NULL) { release_mem_region(bar5, barsize); return 0; } @@ -487,62 +477,6 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) pci_set_master(dev); pci_set_drvdata(dev, (void *) ioaddr); - if (pdev_is_sata(dev)) { - /* make sure IDE0/1 interrupts are not masked */ - irq_mask = (1 << 22) | (1 << 23); - tmp = readl(ioaddr + 0x48); - if (tmp & irq_mask) { - tmp &= ~irq_mask; - writel(tmp, ioaddr + 0x48); - readl(ioaddr + 0x48); /* flush */ - } - writel(0, ioaddr + 0x148); - writel(0, ioaddr + 0x1C8); - } - - writeb(0, ioaddr + 0xB4); - writeb(0, ioaddr + 0xF4); - tmpbyte = readb(ioaddr + 0x4A); - - switch(tmpbyte & 0x30) { - case 0x00: - /* In 100 MHz clocking, try and switch to 133 */ - writeb(tmpbyte|0x10, ioaddr + 0x4A); - break; - case 0x10: - /* On 133Mhz clocking */ - break; - case 0x20: - /* On PCIx2 clocking */ - break; - case 0x30: - /* Clocking is disabled */ - /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, ioaddr + 0x4A); - break; - } - - writeb( 0x72, ioaddr + 0xA1); - writew( 0x328A, ioaddr + 0xA2); - writel(0x62DD62DD, ioaddr + 0xA4); - writel(0x43924392, ioaddr + 0xA8); - writel(0x40094009, ioaddr + 0xAC); - writeb( 0x72, ioaddr + 0xE1); - writew( 0x328A, ioaddr + 0xE2); - writel(0x62DD62DD, ioaddr + 0xE4); - writel(0x43924392, ioaddr + 0xE8); - writel(0x40094009, ioaddr + 0xEC); - - if (pdev_is_sata(dev)) { - writel(0xFFFF0000, ioaddr + 0x108); - writel(0xFFFF0000, ioaddr + 0x188); - writel(0x00680000, ioaddr + 0x148); - writel(0x00680000, ioaddr + 0x1C8); - } - - tmpbyte = readb(ioaddr + 0x4A); - - proc_reports_siimage(dev, (tmpbyte>>4), name); return 1; } @@ -552,55 +486,92 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) * @name: device name * * Perform the initial PCI set up for this device. Attempt to switch - * to 133MHz clocking if the system isn't already set up to do it. + * to 133 MHz clocking if the system isn't already set up to do it. */ -static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, + const char *name) { - u8 rev = dev->revision, tmpbyte = 0, BA5_EN = 0; + unsigned long base, scsc_addr; + void __iomem *ioaddr = NULL; + u8 rev = dev->revision, tmp, BA5_EN; pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255); pci_read_config_byte(dev, 0x8A, &BA5_EN); - if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) { - if (setup_mmio_siimage(dev, name)) { - return 0; + + if ((BA5_EN & 0x01) || pci_resource_start(dev, 5)) + if (setup_mmio_siimage(dev, name)) + ioaddr = pci_get_drvdata(dev); + + base = (unsigned long)ioaddr; + + if (ioaddr && pdev_is_sata(dev)) { + u32 tmp32, irq_mask; + + /* make sure IDE0/1 interrupts are not masked */ + irq_mask = (1 << 22) | (1 << 23); + tmp32 = readl(ioaddr + 0x48); + if (tmp32 & irq_mask) { + tmp32 &= ~irq_mask; + writel(tmp32, ioaddr + 0x48); + readl(ioaddr + 0x48); /* flush */ } + writel(0, ioaddr + 0x148); + writel(0, ioaddr + 0x1C8); + } + + sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80); + sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84); + + scsc_addr = base ? (base + 0x4A) : 0x8A; + tmp = sil_ioread8(dev, scsc_addr); + + switch (tmp & 0x30) { + case 0x00: + /* On 100 MHz clocking, try and switch to 133 MHz */ + sil_iowrite8(dev, tmp | 0x10, scsc_addr); + break; + case 0x30: + /* Clocking is disabled, attempt to force 133MHz clocking. */ + sil_iowrite8(dev, tmp & ~0x20, scsc_addr); + case 0x10: + /* On 133Mhz clocking. */ + break; + case 0x20: + /* On PCIx2 clocking. */ + break; } - pci_write_config_byte(dev, 0x80, 0x00); - pci_write_config_byte(dev, 0x84, 0x00); - pci_read_config_byte(dev, 0x8A, &tmpbyte); - switch(tmpbyte & 0x30) { - case 0x00: - /* 133 clock attempt to force it on */ - pci_write_config_byte(dev, 0x8A, tmpbyte|0x10); - case 0x30: - /* if clocking is disabled */ - /* 133 clock attempt to force it on */ - pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20); - case 0x10: - /* 133 already */ - break; - case 0x20: - /* BIOS set PCI x2 clocking */ - break; + tmp = sil_ioread8(dev, scsc_addr); + + sil_iowrite8 (dev, 0x72, base + 0xA1); + sil_iowrite16(dev, 0x328A, base + 0xA2); + sil_iowrite32(dev, 0x62DD62DD, base + 0xA4); + sil_iowrite32(dev, 0x43924392, base + 0xA8); + sil_iowrite32(dev, 0x40094009, base + 0xAC); + sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1); + sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2); + sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4); + sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8); + sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC); + + if (base && pdev_is_sata(dev)) { + writel(0xFFFF0000, ioaddr + 0x108); + writel(0xFFFF0000, ioaddr + 0x188); + writel(0x00680000, ioaddr + 0x148); + writel(0x00680000, ioaddr + 0x1C8); } - pci_read_config_byte(dev, 0x8A, &tmpbyte); + /* report the clocking mode of the controller */ + if (!pdev_is_sata(dev)) { + static const char *clk_str[] = + { "== 100", "== 133", "== 2X PCI", "DISABLED!" }; - pci_write_config_byte(dev, 0xA1, 0x72); - pci_write_config_word(dev, 0xA2, 0x328A); - pci_write_config_dword(dev, 0xA4, 0x62DD62DD); - pci_write_config_dword(dev, 0xA8, 0x43924392); - pci_write_config_dword(dev, 0xAC, 0x40094009); - pci_write_config_byte(dev, 0xB1, 0x72); - pci_write_config_word(dev, 0xB2, 0x328A); - pci_write_config_dword(dev, 0xB4, 0x62DD62DD); - pci_write_config_dword(dev, 0xB8, 0x43924392); - pci_write_config_dword(dev, 0xBC, 0x40094009); + tmp >>= 4; + printk(KERN_INFO "%s: BASE CLOCK %s\n", name, clk_str[tmp & 3]); + } - proc_reports_siimage(dev, (tmpbyte>>4), name); return 0; } @@ -610,8 +581,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch * * The basic setup here is fairly simple, we can use standard MMIO * operations. However we do have to set the taskfile register offsets - * by hand as there isnt a standard defined layout for them this - * time. + * by hand as there isn't a standard defined layout for them this time. * * The hardware supports buffered taskfiles and also some rather nice * extended PRD tables. For better SI3112 support use the libata driver @@ -622,23 +592,20 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) struct pci_dev *dev = to_pci_dev(hwif->dev); void *addr = pci_get_drvdata(dev); u8 ch = hwif->channel; - unsigned long base; - struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long base; /* - * Fill in the basic HWIF bits + * Fill in the basic hwif bits */ - + hwif->host_flags |= IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); - hwif->hwif_data = addr; + hwif->hwif_data = addr; /* - * Now set up the hw. We have to do this ourselves as - * the MMIO layout isnt the same as the standard port - * based I/O + * Now set up the hw. We have to do this ourselves as the + * MMIO layout isn't the same as the standard port based I/O. */ - memset(io_ports, 0, sizeof(*io_ports)); base = (unsigned long)addr; @@ -648,10 +615,9 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) base += 0x80; /* - * The buffered task file doesn't have status/control - * so we can't currently use it sanely since we want to - * use LBA48 mode. - */ + * The buffered task file doesn't have status/control, so we + * can't currently use it sanely since we want to use LBA48 mode. + */ io_ports->data_addr = base; io_ports->error_addr = base + 1; io_ports->nsect_addr = base + 2; @@ -680,19 +646,17 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) static int is_dev_seagate_sata(ide_drive_t *drive) { - const char *s = &drive->id->model[0]; - unsigned len; - - len = strnlen(s, sizeof(drive->id->model)); + const char *s = &drive->id->model[0]; + unsigned len = strnlen(s, sizeof(drive->id->model)); - if ((len > 4) && (!memcmp(s, "ST", 2))) { + if ((len > 4) && (!memcmp(s, "ST", 2))) if ((!memcmp(s + len - 2, "AS", 2)) || (!memcmp(s + len - 3, "ASL", 3))) { printk(KERN_INFO "%s: applying pessimistic Seagate " "errata fix\n", drive->name); return 1; } - } + return 0; } @@ -709,7 +673,7 @@ static void __devinit sil_quirkproc(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - /* Try and raise the rqsize */ + /* Try and rise the rqsize */ if (!is_sata(hwif) || !is_dev_seagate_sata(drive)) hwif->rqsize = 128; } @@ -743,20 +707,14 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif) * sil_cable_detect - cable detection * @hwif: interface to check * - * Check for the presence of an ATA66 capable cable on the - * interface. + * Check for the presence of an ATA66 capable cable on the interface. */ static u8 __devinit sil_cable_detect(ide_hwif_t *hwif) { - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long addr = siimage_selreg(hwif, 0); - u8 ata66 = 0; - - if (pci_get_drvdata(dev) == NULL) - pci_read_config_byte(dev, addr, &ata66); - else - ata66 = hwif->INB(addr); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long addr = siimage_selreg(hwif, 0); + u8 ata66 = sil_ioread8(dev, addr); return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; } @@ -779,8 +737,15 @@ static const struct ide_port_ops sil_sata_port_ops = { .cable_detect = sil_cable_detect, }; -static struct ide_dma_ops sil_dma_ops = { +static const struct ide_dma_ops sil_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_exec_cmd = ide_dma_exec_cmd, + .dma_start = ide_dma_start, + .dma_end = __ide_dma_end, .dma_test_irq = siimage_dma_test_irq, + .dma_timeout = ide_dma_timeout, + .dma_lost_irq = ide_dma_lost_irq, }; #define DECLARE_SII_DEV(name_str, p_ops) \ @@ -802,15 +767,16 @@ static const struct ide_port_info siimage_chipsets[] __devinitdata = { }; /** - * siimage_init_one - pci layer discovery entry + * siimage_init_one - PCI layer discovery entry * @dev: PCI device * @id: ident table entry * - * Called by the PCI code when it finds an SI680 or SI3112 controller. + * Called by the PCI code when it finds an SiI680 or SiI3112 controller. * We then use the IDE PCI generic helper to do most of the work. */ - -static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) + +static int __devinit siimage_init_one(struct pci_dev *dev, + const struct pci_device_id *id) { struct ide_port_info d; u8 idx = id->driver_data; diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 3cac6b2790dd..48aa019127bc 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -941,6 +941,7 @@ static const struct ide_port_info pmac_port_info = { .port_ops = &pmac_ide_port_ops, .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | IDE_HFLAG_POST_SET_MODE | + IDE_HFLAG_MMIO | IDE_HFLAG_UNMASK_IRQS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 29d833e71cbf..05710c7c1220 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -520,8 +520,11 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf) char *scratch = buf; driver = container_of(drv, struct hpsb_protocol_driver, driver); + id = driver->id_table; + if (!id) + return 0; - for (id = driver->id_table; id->match_flags != 0; id++) { + for (; id->match_flags != 0; id++) { int need_coma = 0; if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) { diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 4e3128ff73c1..fe78f7d25099 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -38,6 +38,7 @@ #include <linux/dma-mapping.h> #include <linux/sched.h> #include <linux/hugetlb.h> +#include <linux/dma-attrs.h> #include "uverbs.h" @@ -72,9 +73,10 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d * @addr: userspace virtual address to start at * @size: length of region to pin * @access: IB_ACCESS_xxx flags for memory being pinned + * @dmasync: flush in-flight DMA when the memory region is written */ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, - size_t size, int access) + size_t size, int access, int dmasync) { struct ib_umem *umem; struct page **page_list; @@ -87,6 +89,10 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, int ret; int off; int i; + DEFINE_DMA_ATTRS(attrs); + + if (dmasync) + dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); if (!can_do_mlock()) return ERR_PTR(-EPERM); @@ -174,10 +180,11 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0); } - chunk->nmap = ib_dma_map_sg(context->device, - &chunk->page_list[0], - chunk->nents, - DMA_BIDIRECTIONAL); + chunk->nmap = ib_dma_map_sg_attrs(context->device, + &chunk->page_list[0], + chunk->nents, + DMA_BIDIRECTIONAL, + &attrs); if (chunk->nmap <= 0) { for (i = 0; i < chunk->nents; ++i) put_page(sg_page(&chunk->page_list[i])); diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 6af2c0f79a67..2acf9b62cf99 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -452,7 +452,7 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ERR_PTR(-ENOMEM); c2mr->pd = c2pd; - c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); + c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(c2mr->umem)) { err = PTR_ERR(c2mr->umem); kfree(c2mr); diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 66eb7030aea8..ed2ee4ba4b7c 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -456,7 +456,8 @@ void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count) ptr = cq->sw_rptr; while (!Q_EMPTY(ptr, cq->sw_wptr)) { cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2)); - if ((SQ_TYPE(*cqe) || (CQE_OPCODE(*cqe) == T3_READ_RESP)) && + if ((SQ_TYPE(*cqe) || + ((CQE_OPCODE(*cqe) == T3_READ_RESP) && wq->oldest_read)) && (CQE_QPID(*cqe) == wq->qpid)) (*count)++; ptr++; @@ -829,7 +830,8 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) wqe->mpaattrs = attr->mpaattrs; wqe->qpcaps = attr->qpcaps; wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss); - wqe->flags = cpu_to_be32(attr->flags); + wqe->rqe_count = cpu_to_be16(attr->rqe_count); + wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type)); wqe->ord = cpu_to_be32(attr->ord); wqe->ird = cpu_to_be32(attr->ird); wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr); @@ -1135,6 +1137,18 @@ int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe, if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) { /* + * If this is an unsolicited read response, then the read + * was generated by the kernel driver as part of peer-2-peer + * connection setup. So ignore the completion. + */ + if (!wq->oldest_read) { + if (CQE_STATUS(*hw_cqe)) + wq->error = 1; + ret = -1; + goto skip_cqe; + } + + /* * Don't write to the HWCQ, so create a new read req CQE * in local memory. */ diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 99543d634704..2bcff7f5046e 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -53,6 +53,7 @@ #define T3_MAX_PBL_SIZE 256 #define T3_MAX_RQ_SIZE 1024 #define T3_MAX_NUM_STAG (1<<15) +#define T3_MAX_MR_SIZE 0x100000000ULL #define T3_STAG_UNSET 0xffffffff diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 969d4d928455..f1a25a821a45 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -278,6 +278,17 @@ enum t3_qp_caps { uP_RI_QP_STAG0_ENABLE = 0x10 } __attribute__ ((packed)); +enum rdma_init_rtr_types { + RTR_READ = 1, + RTR_WRITE = 2, + RTR_SEND = 3, +}; + +#define S_RTR_TYPE 2 +#define M_RTR_TYPE 0x3 +#define V_RTR_TYPE(x) ((x) << S_RTR_TYPE) +#define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE) + struct t3_rdma_init_attr { u32 tid; u32 qpid; @@ -293,7 +304,9 @@ struct t3_rdma_init_attr { u32 ird; u64 qp_dma_addr; u32 qp_dma_size; - u32 flags; + enum rdma_init_rtr_types rtr_type; + u16 flags; + u16 rqe_count; u32 irs; }; @@ -309,8 +322,8 @@ struct t3_rdma_init_wr { u8 mpaattrs; /* 5 */ u8 qpcaps; __be16 ulpdu_size; - __be32 flags; /* bits 31-1 - reservered */ - /* bit 0 - set if RECV posted */ + __be16 flags_rtr_type; + __be16 rqe_count; __be32 ord; /* 6 */ __be32 ird; __be64 qp_dma_addr; /* 7 */ @@ -324,7 +337,7 @@ struct t3_genbit { }; enum rdma_init_wr_flags { - RECVS_POSTED = (1<<0), + MPA_INITIATOR = (1<<0), PRIV_QP = (1<<1), }; diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 6ba4138c8ec3..71554eacb13c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -83,6 +83,7 @@ static void rnic_init(struct iwch_dev *rnicp) rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE; rnicp->attr.max_pds = T3_MAX_NUM_PD - 1; rnicp->attr.mem_pgsizes_bitmask = 0x7FFF; /* 4KB-128MB */ + rnicp->attr.max_mr_size = T3_MAX_MR_SIZE; rnicp->attr.can_resize_wq = 0; rnicp->attr.max_rdma_reads_per_qp = 8; rnicp->attr.max_rdma_read_resources = diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h index 9ad9b1e7c8c1..d2409a505e8d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.h +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -66,6 +66,7 @@ struct iwch_rnic_attributes { * size (4k)^i. Phys block list mode unsupported. */ u32 mem_pgsizes_bitmask; + u64 max_mr_size; u8 can_resize_wq; /* diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 72ca360c3dbc..d44a6df9ad8c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -63,6 +63,10 @@ static char *states[] = { NULL, }; +int peer2peer = 0; +module_param(peer2peer, int, 0644); +MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)"); + static int ep_timeout_secs = 10; module_param(ep_timeout_secs, int, 0644); MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " @@ -125,6 +129,12 @@ static void start_ep_timer(struct iwch_ep *ep) static void stop_ep_timer(struct iwch_ep *ep) { PDBG("%s ep %p\n", __func__, ep); + if (!timer_pending(&ep->timer)) { + printk(KERN_ERR "%s timer stopped when its not running! ep %p state %u\n", + __func__, ep, ep->com.state); + WARN_ON(1); + return; + } del_timer_sync(&ep->timer); put_ep(&ep->com); } @@ -508,7 +518,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) skb_reset_transport_header(skb); len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -559,7 +569,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) set_arp_failure_handler(skb, arp_failure_discard); skb_reset_transport_header(skb); req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(mpalen); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -611,7 +621,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) skb_reset_transport_header(skb); len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -879,6 +889,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) * the MPA header is valid. */ state_set(&ep->com, FPDU_MODE); + ep->mpa_attr.initiator = 1; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -901,8 +912,14 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) /* bind QP and TID with INIT_WR */ err = iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); - if (!err) - goto out; + if (err) + goto err; + + if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) { + iwch_post_zb_read(ep->com.qp); + } + + goto out; err: abort_connection(ep, skb, GFP_KERNEL); out: @@ -995,6 +1012,7 @@ static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb) * If we get here we have accumulated the entire mpa * start reply message including private data. */ + ep->mpa_attr.initiator = 0; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -1065,17 +1083,33 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) PDBG("%s ep %p credits %u\n", __func__, ep, credits); - if (credits == 0) + if (credits == 0) { + PDBG(KERN_ERR "%s 0 credit ack ep %p state %u\n", + __func__, ep, state_read(&ep->com)); return CPL_RET_BUF_DONE; + } + BUG_ON(credits != 1); - BUG_ON(ep->mpa_skb == NULL); - kfree_skb(ep->mpa_skb); - ep->mpa_skb = NULL; dst_confirm(ep->dst); - if (state_read(&ep->com) == MPA_REP_SENT) { - ep->com.rpl_done = 1; - PDBG("waking up ep %p\n", ep); - wake_up(&ep->com.waitq); + if (!ep->mpa_skb) { + PDBG("%s rdma_init wr_ack ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + if (ep->mpa_attr.initiator) { + PDBG("%s initiator ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + if (peer2peer) + iwch_post_zb_read(ep->com.qp); + } else { + PDBG("%s responder ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + ep->com.rpl_done = 1; + wake_up(&ep->com.waitq); + } + } else { + PDBG("%s lsm ack ep %p state %u freeing skb\n", + __func__, ep, state_read(&ep->com)); + kfree_skb(ep->mpa_skb); + ep->mpa_skb = NULL; } return CPL_RET_BUF_DONE; } @@ -1083,8 +1117,11 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) { struct iwch_ep *ep = ctx; + unsigned long flags; + int release = 0; PDBG("%s ep %p\n", __func__, ep); + BUG_ON(!ep); /* * We get 2 abort replies from the HW. The first one must @@ -1095,9 +1132,22 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) return CPL_RET_BUF_DONE; } - close_complete_upcall(ep); - state_set(&ep->com, DEAD); - release_ep_resources(ep); + spin_lock_irqsave(&ep->com.lock, flags); + switch (ep->com.state) { + case ABORTING: + close_complete_upcall(ep); + __state_set(&ep->com, DEAD); + release = 1; + break; + default: + printk(KERN_ERR "%s ep %p state %d\n", + __func__, ep, ep->com.state); + break; + } + spin_unlock_irqrestore(&ep->com.lock, flags); + + if (release) + release_ep_resources(ep); return CPL_RET_BUF_DONE; } @@ -1470,7 +1520,8 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) struct sk_buff *rpl_skb; struct iwch_qp_attributes attrs; int ret; - int state; + int release = 0; + unsigned long flags; if (is_neg_adv_abort(req->status)) { PDBG("%s neg_adv_abort ep %p tid %d\n", __func__, ep, @@ -1488,9 +1539,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) return CPL_RET_BUF_DONE; } - state = state_read(&ep->com); - PDBG("%s ep %p state %u\n", __func__, ep, state); - switch (state) { + spin_lock_irqsave(&ep->com.lock, flags); + PDBG("%s ep %p state %u\n", __func__, ep, ep->com.state); + switch (ep->com.state) { case CONNECTING: break; case MPA_REQ_WAIT: @@ -1536,21 +1587,25 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) break; case DEAD: PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__); + spin_unlock_irqrestore(&ep->com.lock, flags); return CPL_RET_BUF_DONE; default: BUG_ON(1); break; } dst_confirm(ep->dst); + if (ep->com.state != ABORTING) { + __state_set(&ep->com, DEAD); + release = 1; + } + spin_unlock_irqrestore(&ep->com.lock, flags); rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL); if (!rpl_skb) { printk(KERN_ERR MOD "%s - cannot allocate skb!\n", __func__); - dst_release(ep->dst); - l2t_release(L2DATA(ep->com.tdev), ep->l2t); - put_ep(&ep->com); - return CPL_RET_BUF_DONE; + release = 1; + goto out; } rpl_skb->priority = CPL_PRIORITY_DATA; rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl)); @@ -1559,10 +1614,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid)); rpl->cmd = CPL_ABORT_NO_RST; cxgb3_ofld_send(ep->com.tdev, rpl_skb); - if (state != ABORTING) { - state_set(&ep->com, DEAD); +out: + if (release) release_ep_resources(ep); - } return CPL_RET_BUF_DONE; } @@ -1661,15 +1715,18 @@ static void ep_timeout(unsigned long arg) struct iwch_ep *ep = (struct iwch_ep *)arg; struct iwch_qp_attributes attrs; unsigned long flags; + int abort = 1; spin_lock_irqsave(&ep->com.lock, flags); PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid, ep->com.state); switch (ep->com.state) { case MPA_REQ_SENT: + __state_set(&ep->com, ABORTING); connect_reply_upcall(ep, -ETIMEDOUT); break; case MPA_REQ_WAIT: + __state_set(&ep->com, ABORTING); break; case CLOSING: case MORIBUND: @@ -1679,13 +1736,17 @@ static void ep_timeout(unsigned long arg) ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 1); } + __state_set(&ep->com, ABORTING); break; default: - BUG(); + printk(KERN_ERR "%s unexpected state ep %p state %u\n", + __func__, ep, ep->com.state); + WARN_ON(1); + abort = 0; } - __state_set(&ep->com, CLOSING); spin_unlock_irqrestore(&ep->com.lock, flags); - abort_connection(ep, NULL, GFP_ATOMIC); + if (abort) + abort_connection(ep, NULL, GFP_ATOMIC); put_ep(&ep->com); } @@ -1762,16 +1823,19 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if (err) goto err; + /* if needed, wait for wr_ack */ + if (iwch_rqes_posted(qp)) { + wait_event(ep->com.waitq, ep->com.rpl_done); + err = ep->com.rpl_err; + if (err) + goto err; + } + err = send_mpa_reply(ep, conn_param->private_data, conn_param->private_data_len); if (err) goto err; - /* wait for wr_ack */ - wait_event(ep->com.waitq, ep->com.rpl_done); - err = ep->com.rpl_err; - if (err) - goto err; state_set(&ep->com, FPDU_MODE); established_upcall(ep); @@ -1968,40 +2032,39 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep, states[ep->com.state], abrupt); - if (ep->com.state == DEAD) { - PDBG("%s already dead ep %p\n", __func__, ep); - goto out; - } - - if (abrupt) { - if (ep->com.state != ABORTING) { - ep->com.state = ABORTING; - close = 1; - } - goto out; - } - switch (ep->com.state) { case MPA_REQ_WAIT: case MPA_REQ_SENT: case MPA_REQ_RCVD: case MPA_REP_SENT: case FPDU_MODE: - start_ep_timer(ep); - ep->com.state = CLOSING; close = 1; + if (abrupt) + ep->com.state = ABORTING; + else { + ep->com.state = CLOSING; + start_ep_timer(ep); + } break; case CLOSING: - ep->com.state = MORIBUND; close = 1; + if (abrupt) { + stop_ep_timer(ep); + ep->com.state = ABORTING; + } else + ep->com.state = MORIBUND; break; case MORIBUND: + case ABORTING: + case DEAD: + PDBG("%s ignoring disconnect ep %p state %u\n", + __func__, ep, ep->com.state); break; default: BUG(); break; } -out: + spin_unlock_irqrestore(&ep->com.lock, flags); if (close) { if (abrupt) diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 2bb7fbdb3ff4..d7c7e09f0996 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -56,6 +56,7 @@ #define put_ep(ep) { \ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \ ep, atomic_read(&((ep)->kref.refcount))); \ + WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \ kref_put(&((ep)->kref), __free_ep); \ } @@ -225,5 +226,6 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, st int __init iwch_cm_init(void); void __exit iwch_cm_term(void); +extern int peer2peer; #endif /* _IWCH_CM_H_ */ diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index ab4695c1dd56..d07d3a377b5f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -602,7 +602,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mhp) return ERR_PTR(-ENOMEM); - mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc); + mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(mhp->umem)) { err = PTR_ERR(mhp->umem); kfree(mhp); @@ -998,7 +998,7 @@ static int iwch_query_device(struct ib_device *ibdev, props->device_cap_flags = dev->device_cap_flags; props->vendor_id = (u32)dev->rdev.rnic_info.pdev->vendor; props->vendor_part_id = (u32)dev->rdev.rnic_info.pdev->device; - props->max_mr_size = ~0ull; + props->max_mr_size = dev->attr.max_mr_size; props->max_qp = dev->attr.max_qps; props->max_qp_wr = dev->attr.max_wrs; props->max_sge = dev->attr.max_sge_per_wr; diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 61356f91109d..db5100d27ca2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -118,6 +118,7 @@ enum IWCH_QP_FLAGS { }; struct iwch_mpa_attributes { + u8 initiator; u8 recv_marker_enabled; u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */ u8 crc_enabled; @@ -322,6 +323,7 @@ enum iwch_qp_query_flags { IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */ }; +u16 iwch_rqes_posted(struct iwch_qp *qhp); int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr); int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, @@ -331,6 +333,7 @@ int iwch_bind_mw(struct ib_qp *qp, struct ib_mw_bind *mw_bind); int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); +int iwch_post_zb_read(struct iwch_qp *qhp); int iwch_register_device(struct iwch_dev *dev); void iwch_unregister_device(struct iwch_dev *dev); int iwch_quiesce_qps(struct iwch_cq *chp); diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 8891c3b0a3d5..9b4be889c58e 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -586,6 +586,36 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg, } } +int iwch_post_zb_read(struct iwch_qp *qhp) +{ + union t3_wr *wqe; + struct sk_buff *skb; + u8 flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3; + + PDBG("%s enter\n", __func__); + skb = alloc_skb(40, GFP_KERNEL); + if (!skb) { + printk(KERN_ERR "%s cannot send zb_read!!\n", __func__); + return -ENOMEM; + } + wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr)); + memset(wqe, 0, sizeof(struct t3_rdma_read_wr)); + wqe->read.rdmaop = T3_READ_REQ; + wqe->read.reserved[0] = 0; + wqe->read.reserved[1] = 0; + wqe->read.reserved[2] = 0; + wqe->read.rem_stag = cpu_to_be32(1); + wqe->read.rem_to = cpu_to_be64(1); + wqe->read.local_stag = cpu_to_be32(1); + wqe->read.local_len = cpu_to_be32(0); + wqe->read.local_to = cpu_to_be64(1); + wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ)); + wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)| + V_FW_RIWR_LEN(flit_cnt)); + skb->priority = CPL_PRIORITY_DATA; + return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb); +} + /* * This posts a TERMINATE with layer=RDMA, type=catastrophic. */ @@ -671,11 +701,18 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) /* - * Return non zero if at least one RECV was pre-posted. + * Return count of RECV WRs posted */ -static int rqes_posted(struct iwch_qp *qhp) +u16 iwch_rqes_posted(struct iwch_qp *qhp) { - return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV; + union t3_wr *wqe = qhp->wq.queue; + u16 count = 0; + while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) { + count++; + wqe++; + } + PDBG("%s qhp %p count %u\n", __func__, qhp, count); + return count; } static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, @@ -716,8 +753,17 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.ird = qhp->attr.max_ird; init_attr.qp_dma_addr = qhp->wq.dma_addr; init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); - init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0; + init_attr.rqe_count = iwch_rqes_posted(qhp); + init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0; + if (peer2peer) { + init_attr.rtr_type = RTR_READ; + if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) + init_attr.ord = 1; + if (init_attr.ird == 0 && !qhp->attr.mpa_attr.initiator) + init_attr.ird = 1; + } else + init_attr.rtr_type = 0; init_attr.irs = qhp->ep->rcv_seq; PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d " "flags 0x%x qpcaps 0x%x\n", __func__, @@ -832,6 +878,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, abort=0; disconnect = 1; ep = qhp->ep; + get_ep(&ep->com); } flush_qp(qhp, &flag); break; @@ -848,6 +895,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, abort=1; disconnect = 1; ep = qhp->ep; + get_ep(&ep->com); } goto err; break; @@ -929,8 +977,10 @@ out: * on the EP. This can be a normal close (RTS->CLOSING) or * an abnormal close (RTS/CLOSING->ERROR). */ - if (disconnect) + if (disconnect) { iwch_ep_disconnect(ep, abort, GFP_KERNEL); + put_ep(&ep->com); + } /* * If free is 1, then we've disassociated the EP from the QP diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 3d6d9461c31d..00bab60f6de4 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -66,6 +66,7 @@ struct ehca_av; #include "ehca_irq.h" #define EHCA_EQE_CACHE_SIZE 20 +#define EHCA_MAX_NUM_QUEUES 0xffff struct ehca_eqe_cache_entry { struct ehca_eqe *eqe; @@ -127,6 +128,8 @@ struct ehca_shca { /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */ u32 hca_cap_mr_pgsize; int max_mtu; + atomic_t num_cqs; + atomic_t num_qps; }; struct ehca_pd { @@ -344,6 +347,8 @@ extern int ehca_use_hp_mr; extern int ehca_scaling_code; extern int ehca_lock_hcalls; extern int ehca_nr_ports; +extern int ehca_max_cq; +extern int ehca_max_qp; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index ec0cfcf3073f..5540b276a33c 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -132,10 +132,19 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) return ERR_PTR(-EINVAL); + if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) { + ehca_err(device, "Unable to create CQ, max number of %i " + "CQs reached.", ehca_max_cq); + ehca_err(device, "To increase the maximum number of CQs " + "use the number_of_cqs module parameter.\n"); + return ERR_PTR(-ENOSPC); + } + my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL); if (!my_cq) { ehca_err(device, "Out of memory for ehca_cq struct device=%p", device); + atomic_dec(&shca->num_cqs); return ERR_PTR(-ENOMEM); } @@ -305,6 +314,7 @@ create_cq_exit2: create_cq_exit1: kmem_cache_free(cq_cache, my_cq); + atomic_dec(&shca->num_cqs); return cq; } @@ -359,6 +369,7 @@ int ehca_destroy_cq(struct ib_cq *cq) ipz_queue_dtor(NULL, &my_cq->ipz_queue); kmem_cache_free(cq_cache, my_cq); + atomic_dec(&shca->num_cqs); return 0; } diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index b4ac617a70e6..49660dfa1867 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -54,7 +54,8 @@ int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq, const enum ehca_eq_type type, const u32 length) { - u64 ret; + int ret; + u64 h_ret; u32 nr_pages; u32 i; void *vpage; @@ -73,15 +74,15 @@ int ehca_create_eq(struct ehca_shca *shca, return -EINVAL; } - ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, - &eq->pf, - type, - length, - &eq->ipz_eq_handle, - &eq->length, - &nr_pages, &eq->ist); + h_ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, + &eq->pf, + type, + length, + &eq->ipz_eq_handle, + &eq->length, + &nr_pages, &eq->ist); - if (ret != H_SUCCESS) { + if (h_ret != H_SUCCESS) { ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq); return -EINVAL; } @@ -97,24 +98,22 @@ int ehca_create_eq(struct ehca_shca *shca, u64 rpage; vpage = ipz_qpageit_get_inc(&eq->ipz_queue); - if (!vpage) { - ret = H_RESOURCE; + if (!vpage) goto create_eq_exit2; - } rpage = virt_to_abs(vpage); - ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, - eq->ipz_eq_handle, - &eq->pf, - 0, 0, rpage, 1); + h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, + eq->ipz_eq_handle, + &eq->pf, + 0, 0, rpage, 1); if (i == (nr_pages - 1)) { /* last page */ vpage = ipz_qpageit_get_inc(&eq->ipz_queue); - if (ret != H_SUCCESS || vpage) + if (h_ret != H_SUCCESS || vpage) goto create_eq_exit2; } else { - if (ret != H_PAGE_REGISTERED || !vpage) + if (h_ret != H_PAGE_REGISTERED || !vpage) goto create_eq_exit2; } } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 65048976198c..482103eb6eac 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -68,6 +68,8 @@ int ehca_port_act_time = 30; int ehca_static_rate = -1; int ehca_scaling_code = 0; int ehca_lock_hcalls = -1; +int ehca_max_cq = -1; +int ehca_max_qp = -1; module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO); module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); @@ -79,6 +81,8 @@ module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO); module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO); module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); +module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO); +module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO); MODULE_PARM_DESC(open_aqp1, "Open AQP1 on startup (default: no)"); @@ -104,6 +108,12 @@ MODULE_PARM_DESC(scaling_code, MODULE_PARM_DESC(lock_hcalls, "Serialize all hCalls made by the driver " "(default: autodetect)"); +MODULE_PARM_DESC(number_of_cqs, + "Max number of CQs which can be allocated " + "(default: autodetect)"); +MODULE_PARM_DESC(number_of_qps, + "Max number of QPs which can be allocated " + "(default: autodetect)"); DEFINE_RWLOCK(ehca_qp_idr_lock); DEFINE_RWLOCK(ehca_cq_idr_lock); @@ -355,6 +365,25 @@ static int ehca_sense_attributes(struct ehca_shca *shca) if (rblock->memory_page_size_supported & pgsize_map[i]) shca->hca_cap_mr_pgsize |= pgsize_map[i + 1]; + /* Set maximum number of CQs and QPs to calculate EQ size */ + if (ehca_max_qp == -1) + ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES); + else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) { + ehca_gen_err("Requested number of QPs is out of range (1 - %i) " + "specified by HW", rblock->max_qp); + ret = -EINVAL; + goto sense_attributes1; + } + + if (ehca_max_cq == -1) + ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES); + else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) { + ehca_gen_err("Requested number of CQs is out of range (1 - %i) " + "specified by HW", rblock->max_cq); + ret = -EINVAL; + goto sense_attributes1; + } + /* query max MTU from first port -- it's the same for all ports */ port = (struct hipz_query_port *)rblock; h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); @@ -684,7 +713,7 @@ static int __devinit ehca_probe(struct of_device *dev, struct ehca_shca *shca; const u64 *handle; struct ib_pd *ibpd; - int ret, i; + int ret, i, eq_size; handle = of_get_property(dev->node, "ibm,hca-handle", NULL); if (!handle) { @@ -705,6 +734,8 @@ static int __devinit ehca_probe(struct of_device *dev, return -ENOMEM; } mutex_init(&shca->modify_mutex); + atomic_set(&shca->num_cqs, 0); + atomic_set(&shca->num_qps, 0); for (i = 0; i < ARRAY_SIZE(shca->sport); i++) spin_lock_init(&shca->sport[i].mod_sqp_lock); @@ -724,8 +755,9 @@ static int __devinit ehca_probe(struct of_device *dev, goto probe1; } + eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp; /* create event queues */ - ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048); + ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size); if (ret) { ehca_err(&shca->ib_device, "Cannot create EQ."); goto probe1; diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 46ae4eb2c4e1..f974367cad40 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -323,7 +323,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } e_mr->umem = ib_umem_get(pd->uobject->context, start, length, - mr_access_flags); + mr_access_flags, 0); if (IS_ERR(e_mr->umem)) { ib_mr = (void *)e_mr->umem; goto reg_user_mr_exit1; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 57bef1152cc2..18fba92fa7ae 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -421,8 +421,18 @@ static struct ehca_qp *internal_create_qp( u32 swqe_size = 0, rwqe_size = 0, ib_qp_num; unsigned long flags; - if (init_attr->create_flags) + if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) { + ehca_err(pd->device, "Unable to create QP, max number of %i " + "QPs reached.", ehca_max_qp); + ehca_err(pd->device, "To increase the maximum number of QPs " + "use the number_of_qps module parameter.\n"); + return ERR_PTR(-ENOSPC); + } + + if (init_attr->create_flags) { + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); + } memset(&parms, 0, sizeof(parms)); qp_type = init_attr->qp_type; @@ -431,6 +441,7 @@ static struct ehca_qp *internal_create_qp( init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) { ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed", init_attr->sq_sig_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -455,6 +466,7 @@ static struct ehca_qp *internal_create_qp( if (is_llqp && has_srq) { ehca_err(pd->device, "LLQPs can't have an SRQ"); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -466,6 +478,7 @@ static struct ehca_qp *internal_create_qp( ehca_err(pd->device, "no more than three SGEs " "supported for SRQ pd=%p max_sge=%x", pd, init_attr->cap.max_recv_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } } @@ -477,6 +490,7 @@ static struct ehca_qp *internal_create_qp( qp_type != IB_QPT_SMI && qp_type != IB_QPT_GSI) { ehca_err(pd->device, "wrong QP Type=%x", qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -490,6 +504,7 @@ static struct ehca_qp *internal_create_qp( "or max_rq_wr=%x for RC LLQP", init_attr->cap.max_send_wr, init_attr->cap.max_recv_wr); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } break; @@ -497,6 +512,7 @@ static struct ehca_qp *internal_create_qp( if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) { ehca_err(pd->device, "UD LLQP not supported " "by this adapter"); + atomic_dec(&shca->num_qps); return ERR_PTR(-ENOSYS); } if (!(init_attr->cap.max_send_sge <= 5 @@ -508,20 +524,22 @@ static struct ehca_qp *internal_create_qp( "or max_recv_sge=%x for UD LLQP", init_attr->cap.max_send_sge, init_attr->cap.max_recv_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } else if (init_attr->cap.max_send_wr > 255) { ehca_err(pd->device, "Invalid Number of " "max_send_wr=%x for UD QP_TYPE=%x", init_attr->cap.max_send_wr, qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } break; default: ehca_err(pd->device, "unsupported LL QP Type=%x", qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); - break; } } else { int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI @@ -533,6 +551,7 @@ static struct ehca_qp *internal_create_qp( "send_sge=%x recv_sge=%x max_sge=%x", init_attr->cap.max_send_sge, init_attr->cap.max_recv_sge, max_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } } @@ -543,6 +562,7 @@ static struct ehca_qp *internal_create_qp( my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL); if (!my_qp) { ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); + atomic_dec(&shca->num_qps); return ERR_PTR(-ENOMEM); } @@ -823,6 +843,7 @@ create_qp_exit1: create_qp_exit0: kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); return ERR_PTR(ret); } @@ -1948,6 +1969,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, if (HAS_SQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); return 0; } diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c index db4ba92f79fc..9d343b7c2f3b 100644 --- a/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/drivers/infiniband/hw/ipath/ipath_mr.c @@ -195,7 +195,8 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, goto bail; } - umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags); + umem = ib_umem_get(pd->uobject->context, start, length, + mr_access_flags, 0); if (IS_ERR(umem)) return (void *) umem; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 5e570bb0bb6f..2f199c5c4a72 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -137,7 +137,7 @@ static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *cont int err; *umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe), - IB_ACCESS_LOCAL_WRITE); + IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(*umem)) return PTR_ERR(*umem); @@ -221,7 +221,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector } err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, - cq->db.dma, &cq->mcq); + cq->db.dma, &cq->mcq, 0); if (err) goto err_dbmap; diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c index 8e342cc9baec..8aee4233b388 100644 --- a/drivers/infiniband/hw/mlx4/doorbell.c +++ b/drivers/infiniband/hw/mlx4/doorbell.c @@ -63,7 +63,7 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, page->user_virt = (virt & PAGE_MASK); page->refcnt = 0; page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0); + PAGE_SIZE, 0, 0); if (IS_ERR(page->umem)) { err = PTR_ERR(page->umem); kfree(page); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index fe2c2e94a5f8..68e92485fc76 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -132,7 +132,8 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, access_flags); + mr->umem = ib_umem_get(pd->uobject->context, start, length, + access_flags, 0); if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); goto err_free; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 80ea8b9e7761..8e02ecfec188 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -482,7 +482,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, goto err; qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - qp->buf_size, 0); + qp->buf_size, 0, 0); if (IS_ERR(qp->umem)) { err = PTR_ERR(qp->umem); goto err; diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 204619702f9d..12d6bc6f8007 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -109,7 +109,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, } srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - buf_size, 0); + buf_size, 0, 0); if (IS_ERR(srq->umem)) { err = PTR_ERR(srq->umem); goto err_srq; diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 3538da16e3fe..820205dec560 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -818,15 +818,9 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) { - u32 key; - if (!fmr->maps) return; - key = tavor_key_to_hw_index(fmr->ibmr.lkey); - key &= dev->limits.num_mpts - 1; - fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); - fmr->maps = 0; writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); @@ -834,16 +828,9 @@ void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) { - u32 key; - if (!fmr->maps) return; - key = arbel_key_to_hw_index(fmr->ibmr.lkey); - key &= dev->limits.num_mpts - 1; - key = adjust_key(dev, key); - fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); - fmr->maps = 0; *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 696e1f302332..be34f99ca625 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -39,6 +39,8 @@ #include <rdma/ib_smi.h> #include <rdma/ib_umem.h> #include <rdma/ib_user_verbs.h> + +#include <linux/sched.h> #include <linux/mm.h> #include "mthca_dev.h" @@ -367,6 +369,8 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, return ERR_PTR(-EFAULT); } + context->reg_mr_warned = 0; + return &context->ibucontext; } @@ -1006,17 +1010,31 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, struct mthca_dev *dev = to_mdev(pd->device); struct ib_umem_chunk *chunk; struct mthca_mr *mr; + struct mthca_reg_mr ucmd; u64 *pages; int shift, n, len; int i, j, k; int err = 0; int write_mtt_size; + if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) { + if (!to_mucontext(pd->uobject->context)->reg_mr_warned) { + mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n", + current->comm); + mthca_warn(dev, " Update libmthca to fix this.\n"); + } + ++to_mucontext(pd->uobject->context)->reg_mr_warned; + ucmd.mr_attrs = 0; + } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + mr = kmalloc(sizeof *mr, GFP_KERNEL); if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); + mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, + ucmd.mr_attrs & MTHCA_MR_DMASYNC); + if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); goto err; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 262616c8ebb6..934bf9544037 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -67,6 +67,7 @@ struct mthca_ucontext { struct ib_ucontext ibucontext; struct mthca_uar uar; struct mthca_user_db_table *db_tab; + int reg_mr_warned; }; struct mthca_mtt; diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h index 02cc0a766f3a..e1262c942db8 100644 --- a/drivers/infiniband/hw/mthca/mthca_user.h +++ b/drivers/infiniband/hw/mthca/mthca_user.h @@ -61,6 +61,16 @@ struct mthca_alloc_pd_resp { __u32 reserved; }; +struct mthca_reg_mr { +/* + * Mark the memory region with a DMA attribute that causes + * in-flight DMA to be flushed when the region is written to: + */ +#define MTHCA_MR_DMASYNC 0x1 + __u32 mr_attrs; + __u32 reserved; +}; + struct mthca_create_cq { __u32 lkey; __u32 pdn; diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig index 2aeb7ac972a9..d449eb6ec78e 100644 --- a/drivers/infiniband/hw/nes/Kconfig +++ b/drivers/infiniband/hw/nes/Kconfig @@ -2,6 +2,7 @@ config INFINIBAND_NES tristate "NetEffect RNIC Driver" depends on PCI && INET && INFINIBAND select LIBCRC32C + select INET_LRO ---help--- This is a low-level driver for NetEffect RDMA enabled Network Interface Cards (RNIC). diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index a4e9269a29bd..9f7364a9096d 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -91,6 +91,10 @@ unsigned int nes_debug_level = 0; module_param_named(debug_level, nes_debug_level, uint, 0644); MODULE_PARM_DESC(debug_level, "Enable debug output level"); +unsigned int nes_lro_max_aggr = NES_LRO_MAX_AGGR; +module_param(nes_lro_max_aggr, int, NES_LRO_MAX_AGGR); +MODULE_PARM_DESC(nes_mro_max_aggr, " nic LRO MAX packet aggregation"); + LIST_HEAD(nes_adapter_list); static LIST_HEAD(nes_dev_list); diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index cdf2e9ad62f7..1f9f7bf73862 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -173,6 +173,7 @@ extern int disable_mpa_crc; extern unsigned int send_first; extern unsigned int nes_drv_opt; extern unsigned int nes_debug_level; +extern unsigned int nes_lro_max_aggr; extern struct list_head nes_adapter_list; @@ -535,8 +536,8 @@ int nes_register_ofa_device(struct nes_ib_device *); int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *); void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16); void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *); -void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16); -void nes_read_10G_phy_reg(struct nes_device *, u16, u8); +void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16, u16); +void nes_read_10G_phy_reg(struct nes_device *, u8, u8, u16); struct nes_cqp_request *nes_get_cqp_request(struct nes_device *); void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int); int nes_arp_table(struct nes_device *, u32, u8 *, u32); diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index d940fc27129a..9a4b40fae40d 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -594,7 +594,7 @@ static void nes_cm_timer_tick(unsigned long pass) continue; } /* this seems like the correct place, but leave send entry unprotected */ - // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); + /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */ atomic_inc(&send_entry->skb->users); cm_packets_retrans++; nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p," @@ -1335,7 +1335,7 @@ static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb, cm_node->loc_addr, cm_node->loc_port, cm_node->rem_addr, cm_node->rem_port, cm_node->state, atomic_read(&cm_node->ref_count)); - // create event + /* create event */ cm_node->state = NES_CM_STATE_CLOSED; create_event(cm_node, NES_CM_EVENT_ABORTED); @@ -1669,7 +1669,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, if (!cm_node) return NULL; - // set our node side to client (active) side + /* set our node side to client (active) side */ cm_node->tcp_cntxt.client = 1; cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; @@ -1694,7 +1694,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, loopbackremotenode->mpa_frame_size = mpa_frame_size - sizeof(struct ietf_mpa_frame); - // we are done handling this state, set node to a TSA state + /* we are done handling this state, set node to a TSA state */ cm_node->state = NES_CM_STATE_TSA; cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num; loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 08964cc7e98a..8dc70f9bad2f 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -38,6 +38,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/if_vlan.h> +#include <linux/inet_lro.h> #include "nes.h" @@ -832,7 +833,7 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou nes_write_indexed(nesdev, 0x00000900, 0x20000001); nes_write_indexed(nesdev, 0x000060C0, 0x0000028e); nes_write_indexed(nesdev, 0x000060C8, 0x00000020); - // + nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0); /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */ @@ -1207,11 +1208,16 @@ int nes_init_phy(struct nes_device *nesdev) { struct nes_adapter *nesadapter = nesdev->nesadapter; u32 counter = 0; + u32 sds_common_control0; u32 mac_index = nesdev->mac_index; - u32 tx_config; + u32 tx_config = 0; u16 phy_data; + u32 temp_phy_data = 0; + u32 temp_phy_data2 = 0; + u32 i = 0; - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index); if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) { printk(PFX "%s: Programming mdc config for 1G\n", __func__); @@ -1223,7 +1229,7 @@ int nes_init_phy(struct nes_device *nesdev) nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data); nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n", nesadapter->phy_index[mac_index], phy_data); - nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000); + nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000); /* Reset the PHY */ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000); @@ -1277,12 +1283,126 @@ int nes_init_phy(struct nes_device *nesdev) nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data); nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300); } else { - if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) { + if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) || + (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { /* setup 10G MDIO operation */ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); tx_config |= 0x14; nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); } + if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + mdelay(10); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + + /* + * if firmware is already running (like from a + * driver un-load/load, don't do anything. + */ + if (temp_phy_data == temp_phy_data2) { + /* configure QT2505 AMCC PHY */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0x0000, 0x8000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc302, 0x0044); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc318, 0x0052); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528); + + /* + * remove micro from reset; chip boots from ROM, + * uploads EEPROM f/w image, uC executes f/w + */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0002); + + /* + * wait for heart beat to start to + * know loading is done + */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from heartbeat check <this is bad!!!> \n"); + break; + } + mdelay(100); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + } while ((temp_phy_data2 == temp_phy_data)); + + /* + * wait for tracking to start to know + * f/w is good to go + */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7fd); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from status check <this is bad!!!> \n"); + break; + } + mdelay(1000); + /* + * nes_debug(NES_DBG_PHY, "AMCC PHY- phy_status not ready yet = 0x%02X\n", + * temp_phy_data); + */ + } while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70)); + + /* set LOS Control invert RXLOSB_I_PADINV */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd003, 0x0000); + /* set LOS Control to mask of RXLOSB_I */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc314, 0x0042); + /* set LED1 to input mode (LED1 and LED2 share same LED) */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd006, 0x0007); + /* set LED2 to RX link_status and activity */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd007, 0x000A); + /* set LED3 to RX link_status */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd008, 0x0009); + + /* + * reset the res-calibration on t2 + * serdes; ensures it is stable after + * the amcc phy is stable + */ + + sds_common_control0 = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0); + sds_common_control0 |= 0x1; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0); + + /* release the res-calibration reset */ + sds_common_control0 &= 0xfffffffe; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0); + + i = 0; + while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) + && (i++ < 5000)) { + /* mdelay(1); */ + } + + /* + * wait for link train done before moving on, + * or will get an interupt storm + */ + counter = 0; + do { + temp_phy_data = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1))); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from link train wait <this is bad, link didnt train!!!>\n"); + break; + } + mdelay(1); + } while (((temp_phy_data & 0x0f1f0000) != 0x0f0f0000)); + } + } } return 0; } @@ -1375,6 +1495,25 @@ static void nes_rq_wqes_timeout(unsigned long parm) } +static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *priv) +{ + unsigned int ip_len; + struct iphdr *iph; + skb_reset_network_header(skb); + iph = ip_hdr(skb); + if (iph->protocol != IPPROTO_TCP) + return -1; + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + *tcph = tcp_hdr(skb); + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *iphdr = iph; + return 0; +} + + /** * nes_init_nic_qp */ @@ -1520,10 +1659,10 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) } u64temp = (u64)nesvnic->nic.sq_pbase; - nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); + nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); u64temp = (u64)nesvnic->nic.rq_pbase; - nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); + nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP | @@ -1575,7 +1714,7 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) nic_rqe = &nesvnic->nic.rq_vbase[counter]; nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size); nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0; - nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); + nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32)); nesvnic->nic.rx_skb[counter] = skb; } @@ -1592,15 +1731,21 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout; nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic; nes_debug(NES_DBG_INIT, "NAPI support Enabled\n"); - if (nesdev->nesadapter->et_use_adaptive_rx_coalesce) { nes_nic_init_timer(nesdev); if (netdev->mtu > 1500) jumbomode = 1; - nes_nic_init_timer_defaults(nesdev, jumbomode); - } - + nes_nic_init_timer_defaults(nesdev, jumbomode); + } + nesvnic->lro_mgr.max_aggr = NES_LRO_MAX_AGGR; + nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS; + nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc; + nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr; + nesvnic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + nesvnic->lro_mgr.dev = netdev; + nesvnic->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; return 0; } @@ -1620,8 +1765,8 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) /* Free remaining NIC receive buffers */ while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { - nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; - wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); + nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; + wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32; pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); @@ -1704,17 +1849,17 @@ int nes_napi_isr(struct nes_device *nesdev) /* iff NIC, process here, else wait for DPC */ if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) { nesdev->napi_isr_ran = 0; - nes_write32(nesdev->regs+NES_INT_STAT, - (int_stat & - ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3))); + nes_write32(nesdev->regs + NES_INT_STAT, + (int_stat & + ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3))); /* Process the CEQs */ nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]); if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) && - (!nesadapter->et_use_adaptive_rx_coalesce)) || - ((nesadapter->et_use_adaptive_rx_coalesce) && - (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) { + (!nesadapter->et_use_adaptive_rx_coalesce)) || + ((nesadapter->et_use_adaptive_rx_coalesce) && + (nesdev->deepcq_count > nesadapter->et_pkt_rate_low))))) { if ((nesdev->int_req & NES_INT_TIMER) == 0) { /* Enable Periodic timer interrupts */ nesdev->int_req |= NES_INT_TIMER; @@ -1792,12 +1937,12 @@ void nes_dpc(unsigned long param) } if (int_stat) { - if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) { + if (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0| + NES_INT_MAC1|NES_INT_MAC2 | NES_INT_MAC3)) { /* Ack the interrupts */ nes_write32(nesdev->regs+NES_INT_STAT, - (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3))); + (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0| + NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3))); } temp_int_stat = int_stat; @@ -1862,8 +2007,8 @@ void nes_dpc(unsigned long param) } } /* Don't use the interface interrupt bit stay in loop */ - int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3; + int_stat &= ~NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | + NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3; } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS)); if (timer_ints == 1) { @@ -1874,9 +2019,9 @@ void nes_dpc(unsigned long param) nesdev->timer_only_int_count = 0; nesdev->int_req &= ~NES_INT_TIMER; nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req)); - nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req); + nes_write32(nesdev->regs + NES_INT_MASK, ~nesdev->int_req); } else { - nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req)); + nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req)); } } else { if (unlikely(nesadapter->et_use_adaptive_rx_coalesce)) @@ -1884,7 +2029,7 @@ void nes_dpc(unsigned long param) nes_nic_init_timer(nesdev); } nesdev->timer_only_int_count = 0; - nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req)); + nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req)); } } else { nesdev->timer_only_int_count = 0; @@ -1933,7 +2078,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq) do { if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) & NES_CEQE_VALID) { - u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) | + u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX]))); u64temp <<= 1; cq = *((struct nes_hw_cq **)&u64temp); @@ -1961,7 +2106,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq) */ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq) { -// u64 u64temp; + /* u64 u64temp; */ u32 head; u32 aeq_size; u32 aeqe_misc; @@ -1980,8 +2125,10 @@ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq) if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) { if (aeqe_cq_id >= NES_FIRST_QPN) { /* dealing with an accelerated QP related AE */ -// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) | -// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]))); + /* + * u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]))) << 32) | + * ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]))); + */ nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe); } else { /* TODO: dealing with a CQP related AE */ @@ -2081,6 +2228,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) u32 u32temp; u16 phy_data; u16 temp_phy_data; + u32 pcs_val = 0x0f0f0000; + u32 pcs_mask = 0x0f1f0000; spin_lock_irqsave(&nesadapter->phy_lock, flags); if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) { @@ -2144,13 +2293,30 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n", nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0), nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200)); - pcs_control_status = nes_read_indexed(nesdev, - NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200)); - pcs_control_status = nes_read_indexed(nesdev, - NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200)); + + if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_PUMA_1G) { + switch (mac_index) { + case 1: + case 3: + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200); + break; + default: + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0); + break; + } + } else { + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200)); + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200)); + } + nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n", mac_index, pcs_control_status); - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { u32temp = 0x01010000; if (nesadapter->port_count > 2) { u32temp |= 0x02020000; @@ -2159,24 +2325,59 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) phy_data = 0; nes_debug(NES_DBG_PHY, "PCS says the link is down\n"); } - } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) { - nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]); - temp_phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - u32temp = 20; - do { - nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]); - phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - if ((phy_data == temp_phy_data) || (!(--u32temp))) - break; - temp_phy_data = phy_data; - } while (1); - nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", - __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); - } else { - phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0; + switch (nesadapter->phy_type[mac_index]) { + case NES_PHY_TYPE_IRIS: + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + u32temp = 20; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((phy_data == temp_phy_data) || (!(--u32temp))) + break; + temp_phy_data = phy_data; + } while (1); + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); + break; + + case NES_PHY_TYPE_ARGUS: + /* clear the alarms */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc002); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc005); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc006); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005); + /* check link status */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + u32temp = 100; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((phy_data == temp_phy_data) || (!(--u32temp))) + break; + temp_phy_data = phy_data; + } while (1); + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); + break; + + case NES_PHY_TYPE_PUMA_1G: + if (mac_index < 2) + pcs_val = pcs_mask = 0x01010000; + else + pcs_val = pcs_mask = 0x02020000; + /* fall through */ + default: + phy_data = (pcs_val == (pcs_control_status & pcs_mask)) ? 0x4 : 0x0; + break; + } } if (phy_data & 0x0004) { @@ -2185,8 +2386,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n", nesvnic->linkup); if (nesvnic->linkup == 0) { - printk(PFX "The Link is now up for port %u, netdev %p.\n", - mac_index, nesvnic->netdev); + printk(PFX "The Link is now up for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); if (netif_queue_stopped(nesvnic->netdev)) netif_start_queue(nesvnic->netdev); nesvnic->linkup = 1; @@ -2199,8 +2400,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n", nesvnic->linkup); if (nesvnic->linkup == 1) { - printk(PFX "The Link is now down for port %u, netdev %p.\n", - mac_index, nesvnic->netdev); + printk(PFX "The Link is now down for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); if (!(netif_queue_stopped(nesvnic->netdev))) netif_stop_queue(nesvnic->netdev); nesvnic->linkup = 0; @@ -2254,10 +2455,13 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) u16 pkt_type; u16 rqes_processed = 0; u8 sq_cqes = 0; + u8 nes_use_lro = 0; head = cq->cq_head; cq_size = cq->cq_size; cq->cqes_pending = 1; + if (nesvnic->netdev->features & NETIF_F_LRO) + nes_use_lro = 1; do { if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) & NES_NIC_CQE_VALID) { @@ -2272,8 +2476,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) /* bump past the vlan tag */ wqe_fragment_length++; if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) { - u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]); - u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32; + u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX + + wqe_fragment_index * 2]); + u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX + + wqe_fragment_index * 2])) << 32; bus_address = (dma_addr_t)u64temp; if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) { pci_unmap_single(nesdev->pcidev, @@ -2283,8 +2489,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } for (; wqe_fragment_index < 5; wqe_fragment_index++) { if (wqe_fragment_length[wqe_fragment_index]) { - u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]); - u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32; + u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX + + wqe_fragment_index * 2]); + u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX + + wqe_fragment_index * 2])) <<32; bus_address = (dma_addr_t)u64temp; pci_unmap_page(nesdev->pcidev, bus_address, @@ -2331,7 +2539,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) { nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); -// nesadapter->tune_timer.cq_count += cqe_count; + /* nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; cqe_count = 0; nes_replenish_nic_rq(nesvnic); @@ -2379,9 +2587,16 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) >> 16); nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n", nesvnic->netdev->name, vlan_tag); - nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); + if (nes_use_lro) + lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb, + nesvnic->vlan_grp, vlan_tag, NULL); + else + nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); } else { - nes_netif_rx(rx_skb); + if (nes_use_lro) + lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); + else + nes_netif_rx(rx_skb); } } @@ -2399,7 +2614,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) /* Replenish Nic CQ */ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); -// nesdev->nesadapter->tune_timer.cq_count += cqe_count; + /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; cqe_count = 0; } @@ -2413,26 +2628,27 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } while (1); + if (nes_use_lro) + lro_flush_all(&nesvnic->lro_mgr); if (sq_cqes) { barrier(); /* restart the queue if it had been stopped */ if (netif_queue_stopped(nesvnic->netdev)) netif_wake_queue(nesvnic->netdev); } - cq->cq_head = head; /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n", cq->cq_number, cqe_count, cq->cq_head); */ cq->cqe_allocs_pending = cqe_count; if (unlikely(nesadapter->et_use_adaptive_rx_coalesce)) { -// nesdev->nesadapter->tune_timer.cq_count += cqe_count; + /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; nes_nic_tune_timer(nesdev); } if (atomic_read(&nesvnic->rx_skbs_needed)) nes_replenish_nic_rq(nesvnic); - } +} /** @@ -2461,7 +2677,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. - cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | + cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(cq->cq_vbase[head]. cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); cqp = *((struct nes_hw_cqp **)&u64temp); @@ -2478,7 +2694,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. - wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) | + wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]))); cqp_request = *((struct nes_cqp_request **)&u64temp); @@ -2515,7 +2731,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } else { nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n", cqp_request, - le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f); + le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]) & 0x3f); if (cqp_request->dynamic) { kfree(cqp_request); } else { @@ -2529,7 +2745,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; - nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16)); + nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (1 << 16)); if (++cqp->sq_tail >= cqp->sq_size) cqp->sq_tail = 0; @@ -2598,13 +2814,13 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nes_debug(NES_DBG_AEQ, "\n"); aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { - context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); + context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; } else { aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; context = (unsigned long)nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; + aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; BUG_ON(!context); } @@ -2617,7 +2833,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe, nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]); - switch (async_event_id) { case NES_AEQE_AEID_LLP_FIN_RECEIVED: nesqp = *((struct nes_qp **)&context); @@ -3021,7 +3236,7 @@ void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr, cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID); cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32( (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) | - (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]); + (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]); cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32( (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]); } else { diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 8f36e231bdf5..745bf94f3f07 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -33,8 +33,12 @@ #ifndef __NES_HW_H #define __NES_HW_H -#define NES_PHY_TYPE_1G 2 -#define NES_PHY_TYPE_IRIS 3 +#include <linux/inet_lro.h> + +#define NES_PHY_TYPE_1G 2 +#define NES_PHY_TYPE_IRIS 3 +#define NES_PHY_TYPE_ARGUS 4 +#define NES_PHY_TYPE_PUMA_1G 5 #define NES_PHY_TYPE_PUMA_10G 6 #define NES_MULTICAST_PF_MAX 8 @@ -965,7 +969,7 @@ struct nes_arp_entry { #define NES_NIC_CQ_DOWNWARD_TREND 16 struct nes_hw_tune_timer { - //u16 cq_count; + /* u16 cq_count; */ u16 threshold_low; u16 threshold_target; u16 threshold_high; @@ -982,8 +986,10 @@ struct nes_hw_tune_timer { #define NES_TIMER_INT_LIMIT 2 #define NES_TIMER_INT_LIMIT_DYNAMIC 10 #define NES_TIMER_ENABLE_LIMIT 4 -#define NES_MAX_LINK_INTERRUPTS 128 -#define NES_MAX_LINK_CHECK 200 +#define NES_MAX_LINK_INTERRUPTS 128 +#define NES_MAX_LINK_CHECK 200 +#define NES_MAX_LRO_DESCRIPTORS 32 +#define NES_LRO_MAX_AGGR 64 struct nes_adapter { u64 fw_ver; @@ -1183,6 +1189,9 @@ struct nes_vnic { u8 of_device_registered; u8 rdma_enabled; u8 rx_checksum_disabled; + u32 lro_max_aggr; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; }; struct nes_ib_device { diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index e5366b013c1a..1b0938c87774 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -185,12 +185,13 @@ static int nes_netdev_open(struct net_device *netdev) nic_active |= nic_active_bit; nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); - macaddr_high = ((u16)netdev->dev_addr[0]) << 8; + macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; - macaddr_low = ((u32)netdev->dev_addr[2]) << 24; - macaddr_low += ((u32)netdev->dev_addr[3]) << 16; - macaddr_low += ((u32)netdev->dev_addr[4]) << 8; - macaddr_low += (u32)netdev->dev_addr[5]; + + macaddr_low = ((u32)netdev->dev_addr[2]) << 24; + macaddr_low += ((u32)netdev->dev_addr[3]) << 16; + macaddr_low += ((u32)netdev->dev_addr[4]) << 8; + macaddr_low += (u32)netdev->dev_addr[5]; /* Program the various MAC regs */ for (i = 0; i < NES_MAX_PORT_COUNT; i++) { @@ -451,7 +452,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) __le16 *wqe_fragment_length; u32 nr_frags; u32 original_first_length; -// u64 *wqe_fragment_address; + /* u64 *wqe_fragment_address; */ /* first fragment (0) is used by copy buffer */ u16 wqe_fragment_index=1; u16 hoffset; @@ -461,11 +462,12 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) u32 old_head; u32 wqe_misc; - /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," - " (%u frags), tso_size=%u\n", - netdev->name, skb->len, skb_headlen(skb), - skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); - */ + /* + * nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," + * " (%u frags), tso_size=%u\n", + * netdev->name, skb->len, skb_headlen(skb), + * skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); + */ if (!netif_carrier_ok(netdev)) return NETDEV_TX_OK; @@ -795,12 +797,12 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len); printk(PFX "%s: Address length = %d, Address = %s\n", __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data)); - macaddr_high = ((u16)netdev->dev_addr[0]) << 8; + macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; - macaddr_low = ((u32)netdev->dev_addr[2]) << 24; - macaddr_low += ((u32)netdev->dev_addr[3]) << 16; - macaddr_low += ((u32)netdev->dev_addr[4]) << 8; - macaddr_low += (u32)netdev->dev_addr[5]; + macaddr_low = ((u32)netdev->dev_addr[2]) << 24; + macaddr_low += ((u32)netdev->dev_addr[3]) << 16; + macaddr_low += ((u32)netdev->dev_addr[4]) << 8; + macaddr_low += (u32)netdev->dev_addr[5]; for (i = 0; i < NES_MAX_PORT_COUNT; i++) { if (nesvnic->qp_nic_index[i] == 0xf) { @@ -881,12 +883,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) print_mac(mac, multicast_addr->dmi_addr), perfect_filter_register_address+(mc_index * 8), mc_nic_index); - macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; + macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; macaddr_high += (u16)multicast_addr->dmi_addr[1]; - macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24; - macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16; - macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8; - macaddr_low += (u32)multicast_addr->dmi_addr[5]; + macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24; + macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16; + macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8; + macaddr_low += (u32)multicast_addr->dmi_addr[5]; nes_write_indexed(nesdev, perfect_filter_register_address+(mc_index * 8), macaddr_low); @@ -910,23 +912,23 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) /** * nes_netdev_change_mtu */ -static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) +static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; - int ret = 0; - u8 jumbomode=0; + struct nes_device *nesdev = nesvnic->nesdev; + int ret = 0; + u8 jumbomode = 0; - if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) + if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) return -EINVAL; - netdev->mtu = new_mtu; + netdev->mtu = new_mtu; nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN; if (netdev->mtu > 1500) { jumbomode=1; } - nes_nic_init_timer_defaults(nesdev, jumbomode); + nes_nic_init_timer_defaults(nesdev, jumbomode); if (netif_running(netdev)) { nes_netdev_stop(netdev); @@ -936,8 +938,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) return ret; } -#define NES_ETHTOOL_STAT_COUNT 55 -static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = { +static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { "Link Change Interrupts", "Linearized SKBs", "T/GSO Requests", @@ -993,8 +994,12 @@ static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] "CQ Depth 32", "CQ Depth 128", "CQ Depth 256", + "LRO aggregated", + "LRO flushed", + "LRO no_desc", }; +#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) /** * nes_netdev_get_rx_csum @@ -1189,6 +1194,9 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, target_stat_values[52] = int_mod_cq_depth_32; target_stat_values[53] = int_mod_cq_depth_128; target_stat_values[54] = int_mod_cq_depth_256; + target_stat_values[55] = nesvnic->lro_mgr.stats.aggregated; + target_stat_values[56] = nesvnic->lro_mgr.stats.flushed; + target_stat_values[57] = nesvnic->lro_mgr.stats.no_desc; } @@ -1219,14 +1227,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *et_coalesce) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; + struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer; unsigned long flags; - spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); + spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); if (et_coalesce->rx_max_coalesced_frames_low) { - shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low; + shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low; } if (et_coalesce->rx_max_coalesced_frames_irq) { shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq; @@ -1246,14 +1254,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev, nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq; if (et_coalesce->use_adaptive_rx_coalesce) { nesadapter->et_use_adaptive_rx_coalesce = 1; - nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC; + nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC; nesadapter->et_rx_coalesce_usecs_irq = 0; if (et_coalesce->pkt_rate_low) { - nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low; + nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low; } } else { nesadapter->et_use_adaptive_rx_coalesce = 0; - nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT; + nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT; if (nesadapter->et_rx_coalesce_usecs_irq) { nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8))); @@ -1270,28 +1278,28 @@ static int nes_netdev_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *et_coalesce) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; + struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; struct ethtool_coalesce temp_et_coalesce; struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer; unsigned long flags; memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce)); - temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq; - temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce; - temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval; + temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq; + temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce; + temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval; temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low; spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); - temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low; - temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target; + temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low; + temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target; temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high; - temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min; + temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min; temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max; if (nesadapter->et_use_adaptive_rx_coalesce) { temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use; } spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags); - memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce)); + memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce)); return 0; } @@ -1370,30 +1378,38 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd u16 phy_data; et_cmd->duplex = DUPLEX_FULL; - et_cmd->port = PORT_MII; + et_cmd->port = PORT_MII; + if (nesadapter->OneG_Mode) { - et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg; - et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg; et_cmd->speed = SPEED_1000; - nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], - &phy_data); - if (phy_data&0x1000) { - et_cmd->autoneg = AUTONEG_ENABLE; + if (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { + et_cmd->supported = SUPPORTED_1000baseT_Full; + et_cmd->advertising = ADVERTISED_1000baseT_Full; + et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->transceiver = XCVR_INTERNAL; + et_cmd->phy_address = nesdev->mac_index; } else { - et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg; + et_cmd->advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg; + nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data); + if (phy_data & 0x1000) + et_cmd->autoneg = AUTONEG_ENABLE; + else + et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->transceiver = XCVR_EXTERNAL; + et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } - et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } else { - if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) { + if ((nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) || + (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_ARGUS)) { et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->port = PORT_FIBRE; - et_cmd->supported = SUPPORTED_FIBRE; + et_cmd->port = PORT_FIBRE; + et_cmd->supported = SUPPORTED_FIBRE; et_cmd->advertising = ADVERTISED_FIBRE; et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } else { et_cmd->transceiver = XCVR_INTERNAL; - et_cmd->supported = SUPPORTED_10000baseT_Full; + et_cmd->supported = SUPPORTED_10000baseT_Full; et_cmd->advertising = ADVERTISED_10000baseT_Full; et_cmd->phy_address = nesdev->mac_index; } @@ -1416,14 +1432,15 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd struct nes_adapter *nesadapter = nesdev->nesadapter; u16 phy_data; - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G)) { nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data); if (et_cmd->autoneg) { /* Turn on Full duplex, Autoneg, and restart autonegotiation */ phy_data |= 0x1300; } else { - // Turn off autoneg + /* Turn off autoneg */ phy_data &= ~0x1000; } nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], @@ -1454,6 +1471,8 @@ static struct ethtool_ops nes_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, }; @@ -1607,27 +1626,34 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]); if ((nesdev->netdev_count == 0) && - (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) { - nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", - NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1))); + ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) || + ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) && + (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || + ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { + /* + * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", + * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1))); + */ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1))); - u32temp |= 0x00200000; - nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1)), u32temp); + (0x200 * (nesdev->mac_index & 1))); + if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) { + u32temp |= 0x00200000; + nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1)), u32temp); + } + u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1)) ); + (0x200 * (nesdev->mac_index & 1))); + if ((u32temp&0x0f1f0000) == 0x0f0f0000) { - if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) { + if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) { nes_init_phy(nesdev); - nes_read_10G_phy_reg(nesdev, 1, - nesdev->nesadapter->phy_index[nesvnic->logical_port]); + nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); u32temp = 20; do { - nes_read_10G_phy_reg(nesdev, 1, - nesdev->nesadapter->phy_index[nesvnic->logical_port]); + nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); if ((phy_data == temp_phy_data) || (!(--u32temp))) @@ -1644,6 +1670,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); nesvnic->linkup = 1; } + } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { + nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n", + nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn)); + if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) || + ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) { + nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); + nesvnic->linkup = 1; + } } /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index c6d5631a6995..fe83d1b2b177 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -444,15 +444,13 @@ void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 /** * nes_write_10G_phy_reg */ -void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, - u8 phy_addr, u16 data) +void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_addr, u8 dev_addr, u16 phy_reg, + u16 data) { - u32 dev_addr; u32 port_addr; u32 u32temp; u32 counter; - dev_addr = 1; port_addr = phy_addr; /* set address */ @@ -492,14 +490,12 @@ void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, * This routine only issues the read, the data must be read * separately. */ -void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr) +void nes_read_10G_phy_reg(struct nes_device *nesdev, u8 phy_addr, u8 dev_addr, u16 phy_reg) { - u32 dev_addr; u32 port_addr; u32 u32temp; u32 counter; - dev_addr = 1; port_addr = phy_addr; /* set address */ diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index ee74f7c7a6da..99b3c4ae86eb 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1266,7 +1266,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, sq_size = init_attr->cap.max_send_wr; rq_size = init_attr->cap.max_recv_wr; - // check if the encoded sizes are OK or not... + /* check if the encoded sizes are OK or not... */ sq_encoded_size = nes_get_encoded_size(&sq_size); rq_encoded_size = nes_get_encoded_size(&rq_size); @@ -2377,7 +2377,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u8 single_page = 1; u8 stag_key; - region = ib_umem_get(pd->uobject->context, start, length, acc); + region = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(region)) { return (struct ib_mr *)region; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index f1f142dc64b1..9044f8803532 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -95,6 +95,8 @@ enum { IPOIB_MCAST_FLAG_SENDONLY = 1, IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, + + MAX_SEND_CQE = 16, }; #define IPOIB_OP_RECV (1ul << 31) @@ -285,7 +287,8 @@ struct ipoib_dev_priv { u16 pkey_index; struct ib_pd *pd; struct ib_mr *mr; - struct ib_cq *cq; + struct ib_cq *recv_cq; + struct ib_cq *send_cq; struct ib_qp *qp; u32 qkey; @@ -305,6 +308,7 @@ struct ipoib_dev_priv { struct ib_sge tx_sge[MAX_SKB_FRAGS + 1]; struct ib_send_wr tx_wr; unsigned tx_outstanding; + struct ib_wc send_wc[MAX_SEND_CQE]; struct ib_recv_wr rx_wr; struct ib_sge rx_sge[IPOIB_UD_RX_SG]; @@ -662,7 +666,6 @@ static inline int ipoib_register_debugfs(void) { return 0; } static inline void ipoib_unregister_debugfs(void) { } #endif - #define ipoib_printk(level, priv, format, arg...) \ printk(level "%s: " format, ((struct ipoib_dev_priv *) priv)->dev->name , ## arg) #define ipoib_warn(priv, format, arg...) \ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 9db7b0bd9134..97e67d36378f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -249,8 +249,8 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr attr = { .event_handler = ipoib_cm_rx_event_handler, - .send_cq = priv->cq, /* For drain WR */ - .recv_cq = priv->cq, + .send_cq = priv->recv_cq, /* For drain WR */ + .recv_cq = priv->recv_cq, .srq = priv->cm.srq, .cap.max_send_wr = 1, /* For drain WR */ .cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */ @@ -951,8 +951,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr attr = { - .send_cq = priv->cq, - .recv_cq = priv->cq, + .send_cq = priv->recv_cq, + .recv_cq = priv->recv_cq, .srq = priv->cm.srq, .cap.max_send_wr = ipoib_sendq_size, .cap.max_send_sge = 1, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 9a47428366c9..10279b79c44d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -71,7 +71,7 @@ static int ipoib_set_coalesce(struct net_device *dev, coal->rx_max_coalesced_frames > 0xffff) return -EINVAL; - ret = ib_modify_cq(priv->cq, coal->rx_max_coalesced_frames, + ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames, coal->rx_coalesce_usecs); if (ret && ret != -ENOSYS) { ipoib_warn(priv, "failed modifying CQ (%d)\n", ret); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 7cf1fa7074ab..97b815c1a3fc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -364,7 +364,6 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) struct ipoib_dev_priv *priv = netdev_priv(dev); unsigned int wr_id = wc->wr_id; struct ipoib_tx_buf *tx_req; - unsigned long flags; ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", wr_id, wc->status); @@ -384,13 +383,11 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) dev_kfree_skb_any(tx_req->skb); - spin_lock_irqsave(&priv->tx_lock, flags); ++priv->tx_tail; if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && netif_queue_stopped(dev) && test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) netif_wake_queue(dev); - spin_unlock_irqrestore(&priv->tx_lock, flags); if (wc->status != IB_WC_SUCCESS && wc->status != IB_WC_WR_FLUSH_ERR) @@ -399,6 +396,17 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) wc->status, wr_id, wc->vendor_err); } +static int poll_tx(struct ipoib_dev_priv *priv) +{ + int n, i; + + n = ib_poll_cq(priv->send_cq, MAX_SEND_CQE, priv->send_wc); + for (i = 0; i < n; ++i) + ipoib_ib_handle_tx_wc(priv->dev, priv->send_wc + i); + + return n == MAX_SEND_CQE; +} + int ipoib_poll(struct napi_struct *napi, int budget) { struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi); @@ -414,7 +422,7 @@ poll_more: int max = (budget - done); t = min(IPOIB_NUM_WC, max); - n = ib_poll_cq(priv->cq, t, priv->ibwc); + n = ib_poll_cq(priv->recv_cq, t, priv->ibwc); for (i = 0; i < n; i++) { struct ib_wc *wc = priv->ibwc + i; @@ -425,12 +433,8 @@ poll_more: ipoib_cm_handle_rx_wc(dev, wc); else ipoib_ib_handle_rx_wc(dev, wc); - } else { - if (wc->wr_id & IPOIB_OP_CM) - ipoib_cm_handle_tx_wc(dev, wc); - else - ipoib_ib_handle_tx_wc(dev, wc); - } + } else + ipoib_cm_handle_tx_wc(priv->dev, wc); } if (n != t) @@ -439,7 +443,7 @@ poll_more: if (done < budget) { netif_rx_complete(dev, napi); - if (unlikely(ib_req_notify_cq(priv->cq, + if (unlikely(ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && netif_rx_reschedule(dev, napi)) @@ -562,12 +566,16 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, address->last_send = priv->tx_head; ++priv->tx_head; + skb_orphan(skb); if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); netif_stop_queue(dev); } } + + if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) + poll_tx(priv); } static void __ipoib_reap_ah(struct net_device *dev) @@ -714,7 +722,7 @@ void ipoib_drain_cq(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); int i, n; do { - n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc); + n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); for (i = 0; i < n; ++i) { /* * Convert any successful completions to flush @@ -729,14 +737,13 @@ void ipoib_drain_cq(struct net_device *dev) ipoib_cm_handle_rx_wc(dev, priv->ibwc + i); else ipoib_ib_handle_rx_wc(dev, priv->ibwc + i); - } else { - if (priv->ibwc[i].wr_id & IPOIB_OP_CM) - ipoib_cm_handle_tx_wc(dev, priv->ibwc + i); - else - ipoib_ib_handle_tx_wc(dev, priv->ibwc + i); - } + } else + ipoib_cm_handle_tx_wc(dev, priv->ibwc + i); } } while (n == IPOIB_NUM_WC); + + while (poll_tx(priv)) + ; /* nothing */ } int ipoib_ib_dev_stop(struct net_device *dev, int flush) @@ -826,7 +833,7 @@ timeout: msleep(1); } - ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP); + ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP); return 0; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 7a4ed9d3d844..2442090ac8d1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1298,7 +1298,8 @@ static int __init ipoib_init_module(void) ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); - ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE); + ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE, + IPOIB_MIN_QUEUE_SIZE)); #ifdef CONFIG_INFINIBAND_IPOIB_CM ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); #endif diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 07c03f178a49..c1e7ece1fd44 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -171,26 +171,33 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) goto out_free_pd; } - size = ipoib_sendq_size + ipoib_recvq_size + 1; + size = ipoib_recvq_size + 1; ret = ipoib_cm_dev_init(dev); if (!ret) { + size += ipoib_sendq_size; if (ipoib_cm_has_srq(dev)) size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ else size += ipoib_recvq_size * ipoib_max_conn_qp; } - priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); - if (IS_ERR(priv->cq)) { - printk(KERN_WARNING "%s: failed to create CQ\n", ca->name); + priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); + if (IS_ERR(priv->recv_cq)) { + printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name); goto out_free_mr; } - if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP)) - goto out_free_cq; + priv->send_cq = ib_create_cq(priv->ca, NULL, NULL, dev, ipoib_sendq_size, 0); + if (IS_ERR(priv->send_cq)) { + printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name); + goto out_free_recv_cq; + } + + if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP)) + goto out_free_send_cq; - init_attr.send_cq = priv->cq; - init_attr.recv_cq = priv->cq; + init_attr.send_cq = priv->send_cq; + init_attr.recv_cq = priv->recv_cq; if (priv->hca_caps & IB_DEVICE_UD_TSO) init_attr.create_flags = IB_QP_CREATE_IPOIB_UD_LSO; @@ -201,7 +208,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->qp = ib_create_qp(priv->pd, &init_attr); if (IS_ERR(priv->qp)) { printk(KERN_WARNING "%s: failed to create QP\n", ca->name); - goto out_free_cq; + goto out_free_send_cq; } priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff; @@ -230,8 +237,11 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) return 0; -out_free_cq: - ib_destroy_cq(priv->cq); +out_free_send_cq: + ib_destroy_cq(priv->send_cq); + +out_free_recv_cq: + ib_destroy_cq(priv->recv_cq); out_free_mr: ib_dereg_mr(priv->mr); @@ -254,8 +264,11 @@ void ipoib_transport_dev_cleanup(struct net_device *dev) clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); } - if (ib_destroy_cq(priv->cq)) - ipoib_warn(priv, "ib_cq_destroy failed\n"); + if (ib_destroy_cq(priv->send_cq)) + ipoib_warn(priv, "ib_cq_destroy (send) failed\n"); + + if (ib_destroy_cq(priv->recv_cq)) + ipoib_warn(priv, "ib_cq_destroy (recv) failed\n"); ipoib_cm_dev_cleanup(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 431fdeaa2dc4..1cdb5cfb0ff1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -90,6 +90,9 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) } priv->max_ib_mtu = ppriv->max_ib_mtu; + /* MTU will be reset when mcast join happens */ + priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); + priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); priv->pkey = pkey; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index be1b9fbd416d..aeb58cae9a3f 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -473,13 +473,15 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->custom_length = 3; + stats->custom_length = 4; strcpy(stats->custom[0].desc, "qp_tx_queue_full"); stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */ strcpy(stats->custom[1].desc, "fmr_map_not_avail"); stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */; strcpy(stats->custom[2].desc, "eh_abort_cnt"); stats->custom[2].value = conn->eh_abort_cnt; + strcpy(stats->custom[3].desc, "fmr_unalign_cnt"); + stats->custom[3].value = conn->fmr_unalign_cnt; } static int diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 1ee867b1b341..a8c1b300e34d 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -71,6 +71,13 @@ #define iser_dbg(fmt, arg...) \ do { \ + if (iser_debug_level > 1) \ + printk(KERN_DEBUG PFX "%s:" fmt,\ + __func__ , ## arg); \ + } while (0) + +#define iser_warn(fmt, arg...) \ + do { \ if (iser_debug_level > 0) \ printk(KERN_DEBUG PFX "%s:" fmt,\ __func__ , ## arg); \ diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 4a17743a639f..cac50c4dc159 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -334,8 +334,11 @@ static void iser_data_buf_dump(struct iser_data_buf *data, struct scatterlist *sg; int i; + if (iser_debug_level == 0) + return; + for_each_sg(sgl, sg, data->dma_nents, i) - iser_err("sg[%d] dma_addr:0x%lX page:0x%p " + iser_warn("sg[%d] dma_addr:0x%lX page:0x%p " "off:0x%x sz:0x%x dma_len:0x%x\n", i, (unsigned long)ib_sg_dma_address(ibdev, sg), sg_page(sg), sg->offset, @@ -420,6 +423,7 @@ void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask) int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, enum iser_data_dir cmd_dir) { + struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn; struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; struct ib_device *ibdev = device->ib_device; @@ -434,7 +438,8 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - iser_err("rdma alignment violation %d/%d aligned\n", + iscsi_conn->fmr_unalign_cnt++; + iser_warn("rdma alignment violation %d/%d aligned\n", aligned_len, mem->size); iser_data_buf_dump(mem, ibdev); diff --git a/drivers/input/input.c b/drivers/input/input.c index f02c242c3114..27006fc18305 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -898,30 +898,26 @@ static int __init input_proc_init(void) { struct proc_dir_entry *entry; - proc_bus_input_dir = proc_mkdir("input", proc_bus); + proc_bus_input_dir = proc_mkdir("bus/input", NULL); if (!proc_bus_input_dir) return -ENOMEM; proc_bus_input_dir->owner = THIS_MODULE; - entry = create_proc_entry("devices", 0, proc_bus_input_dir); + entry = proc_create("devices", 0, proc_bus_input_dir, + &input_devices_fileops); if (!entry) goto fail1; - entry->owner = THIS_MODULE; - entry->proc_fops = &input_devices_fileops; - - entry = create_proc_entry("handlers", 0, proc_bus_input_dir); + entry = proc_create("handlers", 0, proc_bus_input_dir, + &input_handlers_fileops); if (!entry) goto fail2; - entry->owner = THIS_MODULE; - entry->proc_fops = &input_handlers_fileops; - return 0; fail2: remove_proc_entry("devices", proc_bus_input_dir); - fail1: remove_proc_entry("input", proc_bus); + fail1: remove_proc_entry("bus/input", NULL); return -ENOMEM; } @@ -929,7 +925,7 @@ static void input_proc_exit(void) { remove_proc_entry("devices", proc_bus_input_dir); remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); + remove_proc_entry("bus/input", NULL); } #else /* !CONFIG_PROC_FS */ diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 1457b73850e7..7fb3cf81cfbf 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -159,7 +159,7 @@ static int iforce_usb_probe(struct usb_interface *intf, iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; iforce->cr.wIndex = 0; - iforce->cr.wLength = 16; + iforce->cr.wLength = cpu_to_le16(16); usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index fed3c375ccf3..d8765cc93d27 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -2,33 +2,69 @@ * Driver for PC-speaker like devices found on various Sparc systems. * * Copyright (c) 2002 Vojtech Pavlik - * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net) + * Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> -#include <linux/platform_device.h> +#include <linux/of_device.h> #include <asm/io.h> -#include <asm/ebus.h> -#include <asm/isa.h> MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); +struct grover_beep_info { + void __iomem *freq_regs; + void __iomem *enable_reg; +}; + +struct bbc_beep_info { + u32 clock_freq; + void __iomem *regs; +}; + struct sparcspkr_state { const char *name; - unsigned long iobase; int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); spinlock_t lock; struct input_dev *input_dev; + union { + struct grover_beep_info grover; + struct bbc_beep_info bbc; + } u; }; -static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count) +{ + u32 val, clock_freq = info->clock_freq; + int i; + + if (!count) + return 0; + + if (count <= clock_freq >> 20) + return 1 << 18; + + if (count >= clock_freq >> 12) + return 1 << 10; + + val = 1 << 18; + for (i = 19; i >= 11; i--) { + val >>= 1; + if (count <= clock_freq >> i) + break; + } + + return val; +} + +static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); + struct bbc_beep_info *info = &state->u.bbc; unsigned int count = 0; unsigned long flags; @@ -44,24 +80,29 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in if (value > 20 && value < 32767) count = 1193182 / value; + count = bbc_count_to_reg(info, count); + spin_lock_irqsave(&state->lock, flags); - /* EBUS speaker only has on/off state, the frequency does not - * appear to be programmable. - */ - if (state->iobase & 0x2UL) - outb(!!count, state->iobase); - else - outl(!!count, state->iobase); + if (count) { + outb(0x01, info->regs + 0); + outb(0x00, info->regs + 2); + outb((count >> 16) & 0xff, info->regs + 3); + outb((count >> 8) & 0xff, info->regs + 4); + outb(0x00, info->regs + 5); + } else { + outb(0x00, info->regs + 0); + } spin_unlock_irqrestore(&state->lock, flags); return 0; } -static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); + struct grover_beep_info *info = &state->u.grover; unsigned int count = 0; unsigned long flags; @@ -81,15 +122,15 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int if (count) { /* enable counter 2 */ - outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61); + outb(inb(info->enable_reg) | 3, info->enable_reg); /* set command for counter 2, 2 byte write */ - outb(0xB6, state->iobase + 0x43); + outb(0xB6, info->freq_regs + 1); /* select desired HZ */ - outb(count & 0xff, state->iobase + 0x42); - outb((count >> 8) & 0xff, state->iobase + 0x42); + outb(count & 0xff, info->freq_regs + 0); + outb((count >> 8) & 0xff, info->freq_regs + 0); } else { /* disable counter 2 */ - outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61); + outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg); } spin_unlock_irqrestore(&state->lock, flags); @@ -131,7 +172,7 @@ static int __devinit sparcspkr_probe(struct device *dev) return 0; } -static int __devexit sparcspkr_remove(struct of_device *dev) +static int sparcspkr_shutdown(struct of_device *dev) { struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); struct input_dev *input_dev = state->input_dev; @@ -139,115 +180,180 @@ static int __devexit sparcspkr_remove(struct of_device *dev) /* turn off the speaker */ state->event(input_dev, EV_SND, SND_BELL, 0); - input_unregister_device(input_dev); - - dev_set_drvdata(&dev->dev, NULL); - kfree(state); - return 0; } -static int sparcspkr_shutdown(struct of_device *dev) +static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match) { - struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); - struct input_dev *input_dev = state->input_dev; + struct sparcspkr_state *state; + struct bbc_beep_info *info; + struct device_node *dp; + int err = -ENOMEM; - /* turn off the speaker */ - state->event(input_dev, EV_SND, SND_BELL, 0); + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + goto out_err; + + state->name = "Sparc BBC Speaker"; + state->event = bbc_spkr_event; + spin_lock_init(&state->lock); + + dp = of_find_node_by_path("/"); + err = -ENODEV; + if (!dp) + goto out_free; + + info = &state->u.bbc; + info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0); + if (!info->clock_freq) + goto out_free; + + info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep"); + if (!info->regs) + goto out_free; + + dev_set_drvdata(&op->dev, state); + + err = sparcspkr_probe(&op->dev); + if (err) + goto out_clear_drvdata; return 0; + +out_clear_drvdata: + dev_set_drvdata(&op->dev, NULL); + of_iounmap(&op->resource[0], info->regs, 6); + +out_free: + kfree(state); +out_err: + return err; } -static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match) +static int bbc_remove(struct of_device *op) { - struct linux_ebus_device *edev = to_ebus_device(&dev->dev); - struct sparcspkr_state *state; - int err; + struct sparcspkr_state *state = dev_get_drvdata(&op->dev); + struct input_dev *input_dev = state->input_dev; + struct bbc_beep_info *info = &state->u.bbc; - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; + /* turn off the speaker */ + state->event(input_dev, EV_SND, SND_BELL, 0); - state->name = "Sparc EBUS Speaker"; - state->iobase = edev->resource[0].start; - state->event = ebus_spkr_event; - spin_lock_init(&state->lock); + input_unregister_device(input_dev); - dev_set_drvdata(&dev->dev, state); + of_iounmap(&op->resource[0], info->regs, 6); - err = sparcspkr_probe(&dev->dev); - if (err) { - dev_set_drvdata(&dev->dev, NULL); - kfree(state); - } + dev_set_drvdata(&op->dev, NULL); + kfree(state); return 0; } -static struct of_device_id ebus_beep_match[] = { +static struct of_device_id bbc_beep_match[] = { { .name = "beep", + .compatible = "SUNW,bbc-beep", }, {}, }; -static struct of_platform_driver ebus_beep_driver = { - .name = "beep", - .match_table = ebus_beep_match, - .probe = ebus_beep_probe, - .remove = __devexit_p(sparcspkr_remove), +static struct of_platform_driver bbc_beep_driver = { + .name = "bbcbeep", + .match_table = bbc_beep_match, + .probe = bbc_beep_probe, + .remove = __devexit_p(bbc_remove), .shutdown = sparcspkr_shutdown, }; -static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match) { - struct sparc_isa_device *idev = to_isa_device(&dev->dev); struct sparcspkr_state *state; - int err; + struct grover_beep_info *info; + int err = -ENOMEM; state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) - return -ENOMEM; + goto out_err; - state->name = "Sparc ISA Speaker"; - state->iobase = idev->resource.start; - state->event = isa_spkr_event; + state->name = "Sparc Grover Speaker"; + state->event = grover_spkr_event; spin_lock_init(&state->lock); - dev_set_drvdata(&dev->dev, state); + info = &state->u.grover; + info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq"); + if (!info->freq_regs) + goto out_free; - err = sparcspkr_probe(&dev->dev); - if (err) { - dev_set_drvdata(&dev->dev, NULL); - kfree(state); - } + info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable"); + if (!info->enable_reg) + goto out_unmap_freq_regs; + + dev_set_drvdata(&op->dev, state); + + err = sparcspkr_probe(&op->dev); + if (err) + goto out_clear_drvdata; + + return 0; + +out_clear_drvdata: + dev_set_drvdata(&op->dev, NULL); + of_iounmap(&op->resource[3], info->enable_reg, 1); + +out_unmap_freq_regs: + of_iounmap(&op->resource[2], info->freq_regs, 2); +out_free: + kfree(state); +out_err: + return err; +} + +static int grover_remove(struct of_device *op) +{ + struct sparcspkr_state *state = dev_get_drvdata(&op->dev); + struct grover_beep_info *info = &state->u.grover; + struct input_dev *input_dev = state->input_dev; + + /* turn off the speaker */ + state->event(input_dev, EV_SND, SND_BELL, 0); + + input_unregister_device(input_dev); + + of_iounmap(&op->resource[3], info->enable_reg, 1); + of_iounmap(&op->resource[2], info->freq_regs, 2); + + dev_set_drvdata(&op->dev, NULL); + kfree(state); return 0; } -static struct of_device_id isa_beep_match[] = { +static struct of_device_id grover_beep_match[] = { { - .name = "dma", + .name = "beep", + .compatible = "SUNW,smbus-beep", }, {}, }; -static struct of_platform_driver isa_beep_driver = { - .name = "beep", - .match_table = isa_beep_match, - .probe = isa_beep_probe, - .remove = __devexit_p(sparcspkr_remove), +static struct of_platform_driver grover_beep_driver = { + .name = "groverbeep", + .match_table = grover_beep_match, + .probe = grover_beep_probe, + .remove = __devexit_p(grover_remove), .shutdown = sparcspkr_shutdown, }; static int __init sparcspkr_init(void) { - int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type); + int err = of_register_driver(&bbc_beep_driver, + &of_platform_bus_type); if (!err) { - err = of_register_driver(&isa_beep_driver, &isa_bus_type); + err = of_register_driver(&grover_beep_driver, + &of_platform_bus_type); if (err) - of_unregister_driver(&ebus_beep_driver); + of_unregister_driver(&bbc_beep_driver); } return err; @@ -255,8 +361,8 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - of_unregister_driver(&ebus_beep_driver); - of_unregister_driver(&isa_beep_driver); + of_unregister_driver(&bbc_beep_driver); + of_unregister_driver(&grover_beep_driver); } module_init(sparcspkr_init); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index e1a3a79ab3f9..7ff71ba7b7c9 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/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 1d759f6f8076..55c1134d6137 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -528,9 +528,9 @@ static void aiptek_irq(struct urb *urb) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); - z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); + x = get_unaligned_le16(data + 1); + y = get_unaligned_le16(data + 3); + z = get_unaligned_le16(data + 6); dv = (data[5] & 0x01) != 0 ? 1 : 0; p = (data[5] & 0x02) != 0 ? 1 : 0; @@ -613,8 +613,8 @@ static void aiptek_irq(struct urb *urb) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); + x = get_unaligned_le16(data + 1); + y = get_unaligned_le16(data + 3); jitterable = data[5] & 0x1c; @@ -679,7 +679,7 @@ static void aiptek_irq(struct urb *urb) pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1; - z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); + z = get_unaligned_le16(data + 4); if (dv) { /* If the selected tool changed, reset the old @@ -757,7 +757,7 @@ static void aiptek_irq(struct urb *urb) * hat switches (which just so happen to be the macroKeys.) */ else if (data[0] == 6) { - macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + macro = get_unaligned_le16(data + 1); if (macro > 0) { input_report_key(inputdev, macroKeyEvents[macro - 1], 0); @@ -952,7 +952,7 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data) buf[0], buf[1], buf[2]); ret = -EIO; } else { - ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); + ret = get_unaligned_le16(buf + 1); } kfree(buf); return ret; diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index d2c6da264722..c5a8661a1baa 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -245,11 +245,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, data = report[i]; break; case 2: - data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i])); + data16 = get_unaligned_le16(&report[i]); break; case 3: size = 4; - data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i])); + data32 = get_unaligned_le32(&report[i]); break; } @@ -695,10 +695,10 @@ static void gtco_urb_callback(struct urb *urbinfo) /* Fall thru */ case 1: /* All reports have X and Y coords in the same place */ - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = get_unaligned_le16(&device->buffer[1]); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = get_unaligned_le16(&device->buffer[3]); input_report_abs(inputdev, ABS_Y, val); /* Ditto for proximity bit */ @@ -762,7 +762,7 @@ static void gtco_urb_callback(struct urb *urbinfo) le_buffer[1] = (u8)(device->buffer[4] >> 1); le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); - val = le16_to_cpu(get_unaligned((__le16 *)le_buffer)); + val = get_unaligned_le16(le_buffer); input_report_abs(inputdev, ABS_Y, val); /* @@ -772,10 +772,10 @@ static void gtco_urb_callback(struct urb *urbinfo) buttonbyte = device->buffer[5] >> 1; } else { - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = get_unaligned_le16(&device->buffer[1]); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = get_unaligned_le16(&device->buffer[3]); input_report_abs(inputdev, ABS_Y, val); buttonbyte = device->buffer[5]; @@ -897,7 +897,7 @@ static int gtco_probe(struct usb_interface *usbinterface, dbg("Extra descriptor success: type:%d len:%d", hid_desc->bDescriptorType, hid_desc->wDescriptorLength); - report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); + report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL); if (!report) { err("No more memory for report"); error = -ENOMEM; @@ -913,16 +913,16 @@ static int gtco_probe(struct usb_interface *usbinterface, REPORT_DEVICE_TYPE << 8, 0, /* interface */ report, - hid_desc->wDescriptorLength, + le16_to_cpu(hid_desc->wDescriptorLength), 5000); /* 5 secs */ - if (result == hid_desc->wDescriptorLength) + if (result == le16_to_cpu(hid_desc->wDescriptorLength)) break; } /* If we didn't get the report, fail */ dbg("usb_control_msg result: :%d", result); - if (result != hid_desc->wDescriptorLength) { + if (result != le16_to_cpu(hid_desc->wDescriptorLength)) { err("Failed to get HID Report Descriptor of size: %d", hid_desc->wDescriptorLength); error = -EIO; diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 1182fc133167..f23f5a97fb38 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -63,8 +63,8 @@ static void kbtab_irq(struct urb *urb) goto exit; } - kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1])); - kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3])); + kbtab->x = get_unaligned_le16(&data[1]); + kbtab->y = get_unaligned_le16(&data[3]); kbtab->pressure = (data[5]); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 23ae66c76d47..6ca0bb949ad3 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -350,7 +350,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci) if (ncci == 0xffffffff || np->ncci == ncci) { *pp = (*pp)->next; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if ((mp = np->minorp) != 0) { + if ((mp = np->minorp) != NULL) { #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) capifs_free_ncci(mp->minor); #endif @@ -366,7 +366,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci) } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ kfree(np); - if (*pp == 0) return; + if (*pp == NULL) return; } else { pp = &(*pp)->next; } @@ -483,7 +483,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) #endif goto bad; } - if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); goto bad; } @@ -512,7 +512,7 @@ bad: static void handle_minor_recv(struct capiminor *mp) { struct sk_buff *skb; - while ((skb = skb_dequeue(&mp->inqueue)) != 0) { + while ((skb = skb_dequeue(&mp->inqueue)) != NULL) { unsigned int len = skb->len; mp->inbytes -= len; if (handle_recv_skb(mp, skb) < 0) { @@ -538,7 +538,7 @@ static int handle_minor_send(struct capiminor *mp) return 0; } - while ((skb = skb_dequeue(&mp->outqueue)) != 0) { + while ((skb = skb_dequeue(&mp->outqueue)) != NULL) { datahandle = mp->datahandle; len = (u16)skb->len; skb_push(skb, CAPI_DATA_B3_REQ_LEN); @@ -689,19 +689,19 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (!cdev->ap.applid) return -ENODEV; - if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) { + if ((skb = skb_dequeue(&cdev->recvqueue)) == NULL) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; for (;;) { interruptible_sleep_on(&cdev->recvwait); - if ((skb = skb_dequeue(&cdev->recvqueue)) != 0) + if ((skb = skb_dequeue(&cdev->recvqueue)) != NULL) break; if (signal_pending(current)) break; } - if (skb == 0) + if (skb == NULL) return -ERESTARTNOHAND; } if (skb->len > count) { @@ -940,12 +940,12 @@ capi_ioctl(struct inode *inode, struct file *file, return -EFAULT; mutex_lock(&cdev->ncci_list_mtx); - if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) { + if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) { mutex_unlock(&cdev->ncci_list_mtx); return 0; } #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if ((mp = nccip->minorp) != 0) { + if ((mp = nccip->minorp) != NULL) { count += atomic_read(&mp->ttyopencount); } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -966,7 +966,7 @@ capi_ioctl(struct inode *inode, struct file *file, return -EFAULT; mutex_lock(&cdev->ncci_list_mtx); nccip = capincci_find(cdev, (u32) ncci); - if (!nccip || (mp = nccip->minorp) == 0) { + if (!nccip || (mp = nccip->minorp) == NULL) { mutex_unlock(&cdev->ncci_list_mtx); return -ESRCH; } @@ -986,7 +986,7 @@ capi_open(struct inode *inode, struct file *file) if (file->private_data) return -EEXIST; - if ((file->private_data = capidev_alloc()) == 0) + if ((file->private_data = capidev_alloc()) == NULL) return -ENOMEM; return nonseekable_open(inode, file); @@ -1023,9 +1023,9 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file) struct capiminor *mp; unsigned long flags; - if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0) + if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == NULL) return -ENXIO; - if (mp->nccip == 0) + if (mp->nccip == NULL) return -ENXIO; tty->driver_data = (void *)mp; @@ -1058,7 +1058,7 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file) #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); #endif - if (mp->nccip == 0) + if (mp->nccip == NULL) capiminor_free(mp); } @@ -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) @@ -1526,9 +1529,9 @@ static int __init capi_init(void) char *compileinfo; int major_ret; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index cb42b690b45e..d5b4cc357a3c 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -335,7 +335,7 @@ static capidrv_plci *new_plci(capidrv_contr * card, int chan) plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC); - if (plcip == 0) + if (plcip == NULL) return NULL; plcip->state = ST_PLCI_NONE; @@ -404,7 +404,7 @@ static inline capidrv_ncci *new_ncci(capidrv_contr * card, nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC); - if (nccip == 0) + if (nccip == NULL) return NULL; nccip->ncci = ncci; @@ -426,7 +426,7 @@ static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci) capidrv_plci *plcip; capidrv_ncci *p; - if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) return NULL; for (p = plcip->ncci_list; p; p = p->next) @@ -441,7 +441,7 @@ static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, capidrv_plci *plcip; capidrv_ncci *p; - if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) return NULL; for (p = plcip->ncci_list; p; p = p->next) @@ -755,7 +755,7 @@ static inline int new_bchan(capidrv_contr * card) { int i; for (i = 0; i < card->nbchan; i++) { - if (card->bchans[i].plcip == 0) { + if (card->bchans[i].plcip == NULL) { card->bchans[i].disconnecting = 0; return i; } @@ -877,7 +877,7 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) return; } bchan = &card->bchans[chan]; - if ((plcip = new_plci(card, chan)) == 0) { + if ((plcip = new_plci(card, chan)) == NULL) { printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr); return; } @@ -1388,12 +1388,12 @@ static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) _cdebbuf *cdb = capi_cmsg2str(&s_cmsg); if (cdb) { - printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__, + printk(KERN_DEBUG "%s: applid=%d %s\n", __func__, ap->applid, cdb->buf); cdebbuf_free(cdb); } else printk(KERN_DEBUG "%s: applid=%d %s not traced\n", - __FUNCTION__, ap->applid, + __func__, ap->applid, capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); } if (s_cmsg.Command == CAPI_DATA_B3 @@ -1661,7 +1661,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) NULL, /* Useruserdata */ NULL /* Facilitydataarray */ ); - if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) { + if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) { cmd.command = ISDN_STAT_DHUP; cmd.driver = card->myid; cmd.arg = (c->arg % card->nbchan); @@ -1966,7 +1966,7 @@ static void enable_dchannel_trace(capidrv_contr *card) card->name, errcode); return; } - if (strstr(manufacturer, "AVM") == 0) { + if (strstr(manufacturer, "AVM") == NULL) { printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", card->name, manufacturer); return; @@ -2291,10 +2291,10 @@ static int __init capidrv_init(void) u32 ncontr, contr; u16 errcode; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strncpy(rev, p + 2, sizeof(rev)); rev[sizeof(rev)-1] = 0; - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); @@ -2335,10 +2335,10 @@ static void __exit capidrv_exit(void) char rev[32]; char *p; - if ((p = strchr(revision, ':')) != 0) { + if ((p = strchr(revision, ':')) != NULL) { strncpy(rev, p + 1, sizeof(rev)); rev[sizeof(rev)-1] = 0; - if ((p = strchr(rev, '$')) != 0) + if ((p = strchr(rev, '$')) != NULL) *p = 0; } else { strcpy(rev, " ??? "); diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 6d7c47ec0367..550e80f390a6 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -69,6 +69,7 @@ static int capifs_remount(struct super_block *s, int *flags, char *data) } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) mode = n & ~S_IFMT; else { + kfree(new_opt); printk("capifs: called with bogus options\n"); return -EINVAL; } @@ -189,9 +190,9 @@ static int __init capifs_init(void) char *p; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c index 68409d971e73..fcaa1241ee77 100644 --- a/drivers/isdn/capi/capilib.c +++ b/drivers/isdn/capi/capilib.c @@ -4,7 +4,7 @@ #include <linux/isdn/capilli.h> #define DBG(format, arg...) do { \ -printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ } while (0) struct capilib_msgidqueue { @@ -44,7 +44,7 @@ static inline void mq_init(struct capilib_ncci * np) static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid) { struct capilib_msgidqueue *mq; - if ((mq = np->msgidfree) == 0) + if ((mq = np->msgidfree) == NULL) return 0; np->msgidfree = mq->next; mq->msgid = msgid; diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 22379b94e88f..ebef4ce1b00c 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -450,7 +450,7 @@ static void pars_2_message(_cmsg * cmsg) cmsg->l += 4; break; case _CSTRUCT: - if (*(u8 **) OFF == 0) { + if (*(u8 **) OFF == NULL) { *(cmsg->m + cmsg->l) = '\0'; cmsg->l++; } else if (**(_cstruct *) OFF != 0xff) { diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index f55531869313..75726ea0fbbd 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -10,7 +10,7 @@ * */ -#define CONFIG_AVMB1_COMPAT +#define AVMB1_COMPAT #include "kcapi.h" #include <linux/module.h> @@ -29,7 +29,7 @@ #include <asm/uaccess.h> #include <linux/isdn/capicmd.h> #include <linux/isdn/capiutil.h> -#ifdef CONFIG_AVMB1_COMPAT +#ifdef AVMB1_COMPAT #include <linux/b1lli.h> #endif #include <linux/mutex.h> @@ -154,7 +154,7 @@ static void register_appl(struct capi_ctr *card, u16 applid, capi_register_param if (card) card->register_appl(card, applid, rparam); else - printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__); + printk(KERN_WARNING "%s: cannot get card resources\n", __func__); } @@ -178,7 +178,7 @@ static void notify_up(u32 contr) printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); } if (!card) { - printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr); + printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); return; } for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { @@ -740,7 +740,7 @@ u16 capi20_get_profile(u32 contr, struct capi_profile *profp) EXPORT_SYMBOL(capi20_get_profile); -#ifdef CONFIG_AVMB1_COMPAT +#ifdef AVMB1_COMPAT static int old_capi_manufacturer(unsigned int cmd, void __user *data) { avmb1_loadandconfigdef ldef; @@ -826,7 +826,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) card = capi_ctr_get(card); if (!card) return -ESRCH; - if (card->load_firmware == 0) { + if (card->load_firmware == NULL) { printk(KERN_DEBUG "kcapi: load: no load function\n"); return -ESRCH; } @@ -835,7 +835,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); return -EINVAL; } - if (ldef.t4file.data == 0) { + if (ldef.t4file.data == NULL) { printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); return -EINVAL; } @@ -904,7 +904,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) struct capi_ctr *card; switch (cmd) { -#ifdef CONFIG_AVMB1_COMPAT +#ifdef AVMB1_COMPAT case AVMB1_LOAD: case AVMB1_LOAD_AND_CONFIG: case AVMB1_RESETCARD: @@ -951,7 +951,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) if (strcmp(driver->name, cdef.driver) == 0) break; } - if (driver == 0) { + if (driver == NULL) { printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", cdef.driver); return -ESRCH; @@ -1004,9 +1004,9 @@ static int __init kcapi_init(void) return ret; kcapi_proc_init(); - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h index 1cb2c40f9921..244711f7f838 100644 --- a/drivers/isdn/capi/kcapi.h +++ b/drivers/isdn/capi/kcapi.h @@ -17,7 +17,7 @@ #ifdef KCAPI_DEBUG #define DBG(format, arg...) do { \ -printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ } while (0) #else #define DBG(format, arg...) /* */ diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index 845a797b0030..c29208bd7521 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -114,6 +114,7 @@ static int seq_contrstats_open(struct inode *inode, struct file *file) } static const struct file_operations proc_controller_ops = { + .owner = THIS_MODULE, .open = seq_controller_open, .read = seq_read, .llseek = seq_lseek, @@ -121,6 +122,7 @@ static const struct file_operations proc_controller_ops = { }; static const struct file_operations proc_contrstats_ops = { + .owner = THIS_MODULE, .open = seq_contrstats_open, .read = seq_read, .llseek = seq_lseek, @@ -219,6 +221,7 @@ seq_applstats_open(struct inode *inode, struct file *file) } static const struct file_operations proc_applications_ops = { + .owner = THIS_MODULE, .open = seq_applications_open, .read = seq_read, .llseek = seq_lseek, @@ -226,21 +229,13 @@ static const struct file_operations proc_applications_ops = { }; static const struct file_operations proc_applstats_ops = { + .owner = THIS_MODULE, .open = seq_applstats_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static void -create_seq_entry(char *name, mode_t mode, const struct file_operations *f) -{ - struct proc_dir_entry *entry; - entry = create_proc_entry(name, mode, NULL); - if (entry) - entry->proc_fops = f; -} - // --------------------------------------------------------------------------- static void *capi_driver_start(struct seq_file *seq, loff_t *pos) @@ -283,6 +278,7 @@ seq_capi_driver_open(struct inode *inode, struct file *file) } static const struct file_operations proc_driver_ops = { + .owner = THIS_MODULE, .open = seq_capi_driver_open, .read = seq_read, .llseek = seq_lseek, @@ -296,11 +292,11 @@ kcapi_proc_init(void) { proc_mkdir("capi", NULL); proc_mkdir("capi/controllers", NULL); - create_seq_entry("capi/controller", 0, &proc_controller_ops); - create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops); - create_seq_entry("capi/applications", 0, &proc_applications_ops); - create_seq_entry("capi/applstats", 0, &proc_applstats_ops); - create_seq_entry("capi/driver", 0, &proc_driver_ops); + proc_create("capi/controller", 0, NULL, &proc_controller_ops); + proc_create("capi/contrstats", 0, NULL, &proc_contrstats_ops); + proc_create("capi/applications", 0, NULL, &proc_applications_ops); + proc_create("capi/applstats", 0, NULL, &proc_applstats_ops); + proc_create("capi/driver", 0, NULL, &proc_driver_ops); } void __exit diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 4fd4c46892e3..8b256a617c8a 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -288,13 +288,12 @@ divert_dev_init(void) isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); if (!isdn_proc_entry) return (-1); - isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry); + isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO, + isdn_proc_entry, &isdn_fops); if (!isdn_divert_entry) { remove_proc_entry("isdn", init_net.proc_net); return (-1); } - isdn_divert_entry->proc_fops = &isdn_fops; - isdn_divert_entry->owner = THIS_MODULE; #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index fceeb1d57682..45d1ee93cd39 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/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 4484a6417235..abf05ec31760 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -661,11 +661,11 @@ int b1ctl_read_proc(char *page, char **start, off_t off, len += sprintf(page+len, "%-16s %s\n", "type", s); if (card->cardtype == avm_t1isa) len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -788,9 +788,9 @@ static int __init b1_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 669f6f67449c..da34b98e3de7 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -883,11 +883,11 @@ int b1dmactl_read_proc(char *page, char **start, off_t off, default: s = "???"; break; } len += sprintf(page+len, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -970,9 +970,9 @@ static int __init b1dma_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c index 80fb488848b8..1e288eeb5e2a 100644 --- a/drivers/isdn/hardware/avm/b1isa.c +++ b/drivers/isdn/hardware/avm/b1isa.c @@ -203,9 +203,9 @@ static int __init b1isa_init(void) char rev[32]; int i; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c index 90e2e6643d19..5b314a2c4049 100644 --- a/drivers/isdn/hardware/avm/b1pci.c +++ b/drivers/isdn/hardware/avm/b1pci.c @@ -382,9 +382,9 @@ static int __init b1pci_init(void) char rev[32]; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c index e479c0aef38d..7740403b40e1 100644 --- a/drivers/isdn/hardware/avm/b1pcmcia.c +++ b/drivers/isdn/hardware/avm/b1pcmcia.c @@ -201,9 +201,9 @@ static int __init b1pcmcia_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 4bbbbe688077..9df1d3f66c87 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -1088,11 +1088,11 @@ static int c4_read_proc(char *page, char **start, off_t off, default: s = "???"; break; } len += sprintf(page+len, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -1167,7 +1167,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, } card->mbase = ioremap(card->membase, 128); - if (card->mbase == 0) { + if (card->mbase == NULL) { printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n", card->membase); retval = -EIO; @@ -1291,9 +1291,9 @@ static int __init c4_init(void) char rev[32]; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 6130724e46e7..e7724493738c 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -551,9 +551,9 @@ static int __init t1isa_init(void) char *p; int i; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c index d1e253c94db4..e6d298d75146 100644 --- a/drivers/isdn/hardware/avm/t1pci.c +++ b/drivers/isdn/hardware/avm/t1pci.c @@ -233,9 +233,9 @@ static int __init t1pci_init(void) char rev[32]; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 6d39f9360766..5fcbdccd7a53 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -393,7 +393,7 @@ void diva_free_dma_map(void *hdev, struct _diva_dma_map_entry *pmap) dma_addr_t dma_handle; void *addr_handle; - for (i = 0; (pmap != 0); i++) { + for (i = 0; (pmap != NULL); i++) { diva_get_dma_map_entry(pmap, i, &cpu_addr, &phys_addr); if (!cpu_addr) { break; diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 0632a2606998..fae895828a17 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -125,15 +125,11 @@ static const struct file_operations divas_fops = { int create_divas_proc(void) { - divas_proc_entry = create_proc_entry(divas_proc_name, - S_IFREG | S_IRUGO, - proc_net_eicon); + proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon, + &divas_fops); if (!divas_proc_entry) return (0); - divas_proc_entry->proc_fops = &divas_fops; - divas_proc_entry->owner = THIS_MODULE; - return (1); } diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 1ff98e7eb794..599fed88222d 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -742,7 +742,7 @@ static void start_internal_command (dword Id, PLCI *plci, t_std_internal_comma else { i = 1; - while (plci->internal_command_queue[i] != 0) + while (plci->internal_command_queue[i] != NULL) i++; plci->internal_command_queue[i] = command_function; } @@ -758,7 +758,7 @@ static void next_internal_command (dword Id, PLCI *plci) plci->internal_command = 0; plci->internal_command_queue[0] = NULL; - while (plci->internal_command_queue[1] != 0) + while (plci->internal_command_queue[1] != NULL) { for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++) plci->internal_command_queue[i] = plci->internal_command_queue[i+1]; @@ -9119,7 +9119,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho dbug(1,dprintf("AdvSigPlci=0x%x",a->AdvSignalPLCI)); return 0x2001; /* codec in use by another application */ } - if(plci!=0) + if(plci!=NULL) { a->AdvSignalPLCI = plci; plci->tel=ADV_VOICE; @@ -9144,7 +9144,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho } /* indicate D-ch connect if */ } /* codec is connected OK */ - if(plci!=0) + if(plci!=NULL) { a->AdvSignalPLCI = plci; plci->tel=ADV_VOICE; @@ -9170,7 +9170,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho { if(hook_listen) return 0x300B; /* Facility not supported */ /* no hook with SCOM */ - if(plci!=0) plci->tel = CODEC; + if(plci!=NULL) plci->tel = CODEC; dbug(1,dprintf("S/SCOM codec")); /* first time we use the scom-s codec we must shut down the internal */ /* handset application of the card. This can be done by an assign with */ @@ -14604,7 +14604,7 @@ static void channel_xmit_extended_xon (PLCI * plci) { int max_ch = ARRAY_SIZE(a->ch_flow_control); int i, one_requested = 0; - if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) { + if ((!plci) || (!plci->Id) || ((a = plci->adapter) == NULL)) { return; } diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index b96f3184c2e5..1f879b500d83 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -344,7 +344,7 @@ setup_asuscom(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 0f1db1f669b2..7cabc5a19492 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -797,7 +797,7 @@ static int __devinit avm_pnp_setup(struct IsdnCardState *cs) err = pnp_activate_dev(pnp_avm_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } cs->hw.avm.cfg_reg = diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 2d670856d141..018bd293e580 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1088,7 +1088,7 @@ static int __devinit setup_diva_isapnp(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 2c3691fda300..aa29d1cf16af 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -937,7 +937,7 @@ setup_elsa_isapnp(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index f4a213877e35..d92e8d6c2ae2 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1417,7 +1417,7 @@ setup_hfcsx(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 98b0149bca68..8df889b0c1a9 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -905,7 +905,7 @@ rx_int_complete(struct urb *urb) if (status) { printk(KERN_INFO "HFC-S USB: %s error resubmitting URB fifo(%d)\n", - __FUNCTION__, fifon); + __func__, fifon); } } @@ -1543,14 +1543,14 @@ hfc_usb_disconnect(struct usb_interface *intf) stop_isoc_chain(&context->fifos[i]); DBG(HFCUSB_DBG_INIT, "HFC-S USB: %s stopping ISOC chain Fifo(%i)", - __FUNCTION__, i); + __func__, i); } } else { if (context->fifos[i].active > 0) { context->fifos[i].active = 0; DBG(HFCUSB_DBG_INIT, "HFC-S USB: %s unlinking URB for Fifo(%i)", - __FUNCTION__, i); + __func__, i); } usb_kill_urb(context->fifos[i].urb); usb_free_urb(context->fifos[i].urb); diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c index 909d6709ec16..cf082665cc8b 100644 --- a/drivers/isdn/hisax/hfcscard.c +++ b/drivers/isdn/hisax/hfcscard.c @@ -193,7 +193,7 @@ setup_hfcs(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h index ceafecdb1037..5ed3b1c44184 100644 --- a/drivers/isdn/hisax/hisax_debug.h +++ b/drivers/isdn/hisax/hisax_debug.h @@ -27,14 +27,14 @@ #define DBG(level, format, arg...) do { \ if (level & __debug_variable) \ -printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ } while (0) #define DBG_PACKET(level,data,count) \ - if (level & __debug_variable) dump_packet(__FUNCTION__,data,count) + if (level & __debug_variable) dump_packet(__func__,data,count) #define DBG_SKB(level,skb) \ - if ((level & __debug_variable) && skb) dump_packet(__FUNCTION__,skb->data,skb->len) + if ((level & __debug_variable) && skb) dump_packet(__func__,skb->data,skb->len) static void __attribute__((unused)) diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 76043dedba5b..c0b4db2f8364 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -68,7 +68,7 @@ static struct pci_device_id fcpci_ids[] = { MODULE_DEVICE_TABLE(pci, fcpci_ids); -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP static struct pnp_device_id fcpnp_ids[] __devinitdata = { { .id = "AVM0900", @@ -914,7 +914,7 @@ static int __devinit fcpci_probe(struct pci_dev *pdev, return retval; } -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) { struct fritz_adapter *adapter; @@ -935,7 +935,7 @@ static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_i pnp_disable_dev(pdev); retval = pnp_activate_dev(pdev); if (retval < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__, + printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__, (char *)dev_id->driver_data, retval); goto err_free; } @@ -974,6 +974,8 @@ static struct pnp_driver fcpnp_driver = { .remove = __devexit_p(fcpnp_remove), .id_table = fcpnp_ids, }; +#else +static struct pnp_driver fcpnp_driver; #endif static void __devexit fcpci_remove(struct pci_dev *pdev) @@ -1001,7 +1003,7 @@ static int __init hisax_fcpcipnp_init(void) retval = pci_register_driver(&fcpci_driver); if (retval) return retval; -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP retval = pnp_register_driver(&fcpnp_driver); if (retval < 0) { pci_unregister_driver(&fcpci_driver); @@ -1013,7 +1015,7 @@ static int __init hisax_fcpcipnp_init(void) static void __exit hisax_fcpcipnp_exit(void) { -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP pnp_unregister_driver(&fcpnp_driver); #endif pci_unregister_driver(&fcpci_driver); diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index 2d18d4f1e57e..a92bf0d2cab2 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -252,7 +252,7 @@ setup_ix1micro(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 421b8e6763d7..ef00633e1d2a 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -255,7 +255,7 @@ int __devinit setup_niccy(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err < 0) { printk(KERN_WARNING "%s: pnp_activate_dev " - "ret(%d)\n", __FUNCTION__, err); + "ret(%d)\n", __func__, err); return 0; } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 95425f3d2220..a10dfa82c734 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -555,7 +555,7 @@ setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index 04416bad611d..2044e7173ab4 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -218,13 +218,13 @@ enum { #define L1_EVENT_COUNT (EV_TIMER3 + 1) #define ERR(format, arg...) \ -printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) +printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #define WARN(format, arg...) \ -printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) +printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #define INFO(format, arg...) \ -printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) +printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #include "isdnhdlc.h" #include "fsm.h" @@ -406,7 +406,7 @@ struct st5481_adapter { /* * Submit an URB with error reporting. This is a macro so - * the __FUNCTION__ returns the caller function name. + * the __func__ returns the caller function name. */ #define SUBMIT_URB(urb, mem_flags) \ ({ \ @@ -470,7 +470,7 @@ extern int st5481_debug; #ifdef CONFIG_HISAX_DEBUG #define DBG_ISO_PACKET(level,urb) \ - if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb) + if (level & __debug_variable) dump_iso_packet(__func__,urb) static void __attribute__((unused)) dump_iso_packet(const char *name, struct urb *urb) diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 4ada66b8b679..427a8b0520f5 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -342,7 +342,7 @@ void st5481_release_usb(struct st5481_adapter *adapter) usb_kill_urb(intr->urb); kfree(intr->urb->transfer_buffer); usb_free_urb(intr->urb); - ctrl->urb = NULL; + intr->urb = NULL; } /* diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index 6a5e379e0774..5dc9f1a43629 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -301,7 +301,7 @@ setup_teles3(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[3] = pnp_port_start(pnp_d, 2); diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 27d890b48f88..15906d005b05 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -370,6 +370,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) /******************************************************/ static const struct file_operations conf_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = hysdn_conf_read, .write = hysdn_conf_write, @@ -402,11 +403,10 @@ hysdn_procconf_init(void) while (card) { sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); - if ((card->procconf = (void *) create_proc_entry(conf_name, - S_IFREG | S_IRUGO | S_IWUSR, - hysdn_proc_entry)) != NULL) { - ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; - ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE; + if ((card->procconf = (void *) proc_create(conf_name, + S_IFREG | S_IRUGO | S_IWUSR, + hysdn_proc_entry, + &conf_fops)) != NULL) { hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 27b3991fb0ec..8991d2c8ee4a 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -380,6 +380,7 @@ hysdn_log_poll(struct file *file, poll_table * wait) /**************************************************/ static const struct file_operations log_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = hysdn_log_read, .write = hysdn_log_write, @@ -402,10 +403,9 @@ hysdn_proclog_init(hysdn_card * card) if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); - if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - pd->log->proc_fops = &log_fops; - pd->log->owner = THIS_MODULE; - } + pd->log = proc_create(pd->log_name, + S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry, + &log_fops); init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index d4ad6992f776..0f3c66de69bc 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1924,7 +1924,7 @@ isdn_free_channel(int di, int ch, int usage) if ((di < 0) || (ch < 0)) { printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n", - __FUNCTION__, di, ch); + __func__, di, ch); return; } for (i = 0; i < ISDN_MAX_CHANNELS; i++) diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index bc2f0dd962ea..be4949715d55 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -108,7 +108,7 @@ static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local * lp = nd->queue; // printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n", -// __FUNCTION__, lp->name, lp, nlp->name, nlp, lp->last); +// __func__, lp->name, lp, nlp->name, nlp, lp->last); nlp->last = lp->last; lp->last->next = nlp; lp->last = nlp; @@ -129,7 +129,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) master_lp = (isdn_net_local *) lp->master->priv; // printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", -// __FUNCTION__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); +// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); lp->last->next = lp->next; lp->next->last = lp->last; @@ -141,7 +141,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) } lp->next = lp->last = lp; /* (re)set own pointers */ // printk(KERN_DEBUG "%s: mndq(%p)\n", -// __FUNCTION__, master_lp->netdev->queue); +// __func__, master_lp->netdev->queue); spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); } diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 9f5fe372f83d..127cfdad68e7 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -110,7 +110,7 @@ isdn_ppp_free(isdn_net_local * lp) if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return 0; } @@ -127,7 +127,7 @@ isdn_ppp_free(isdn_net_local * lp) #endif /* CONFIG_ISDN_MPP */ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return 0; } is = ippp_table[lp->ppp_slot]; @@ -226,7 +226,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp) { if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return; } ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; @@ -245,7 +245,7 @@ isdn_ppp_closewait(int slot) if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return 0; } is = ippp_table[slot]; @@ -343,7 +343,7 @@ isdn_ppp_release(int min, struct file *file) is = file->private_data; if (!is) { - printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__); + printk(KERN_ERR "%s: no file->private_data\n", __func__); return; } if (is->debug & 0x1) @@ -353,7 +353,7 @@ isdn_ppp_release(int min, struct file *file) isdn_net_dev *p = is->lp->netdev; if (!p) { - printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__); + printk(KERN_ERR "%s: no lp->netdev\n", __func__); return; } is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */ @@ -1080,7 +1080,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); if (net_dev->local->ppp_slot < 0) { printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __FUNCTION__, net_dev->local->ppp_slot); + __func__, net_dev->local->ppp_slot); goto drop_packet; } if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { @@ -1107,7 +1107,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff skb_old->len); if (net_dev->local->ppp_slot < 0) { printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __FUNCTION__, net_dev->local->ppp_slot); + __func__, net_dev->local->ppp_slot); goto drop_packet; } pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, @@ -1553,7 +1553,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) if (lp->ppp_slot < 0) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return(-EINVAL); } @@ -1604,7 +1604,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, slot = lp->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); stats->frame_drops++; dev_kfree_skb(skb); spin_unlock_irqrestore(&mp->lock, flags); @@ -1641,7 +1641,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, slot = lpq->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", - __FUNCTION__, lpq->ppp_slot); + __func__, lpq->ppp_slot); } else { u32 lls = ippp_table[slot]->last_link_seqno; if (MP_LT(lls, minseq)) @@ -1875,7 +1875,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return; } if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { @@ -2655,7 +2655,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, lp->ppp_slot); if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return; } is = ippp_table[lp->ppp_slot]; @@ -2665,7 +2665,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return; } mis = ippp_table[slot]; @@ -2829,7 +2829,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct return; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return; } is = ippp_table[slot]; @@ -2852,7 +2852,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return; } mis = ippp_table[slot]; diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 133eb18e65cc..1a2222cbb805 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1347,17 +1347,19 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file) modem_info *info = (modem_info *) tty->driver_data; u_char control, status; - if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) + if (isdn_tty_paranoia_check(info, tty->name, __func__)) return -ENODEV; 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) @@ -1372,7 +1374,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, { modem_info *info = (modem_info *) tty->driver_data; - if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) + if (isdn_tty_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -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; - } } } @@ -1608,7 +1598,7 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) return -ENODEV; if (!try_module_get(info->owner)) { - printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__); + printk(KERN_WARNING "%s: cannot reserve module\n", __func__); return -ENODEV; } #ifdef ISDN_DEBUG_MODEM_OPEN @@ -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/leds/led-class.c b/drivers/leds/led-class.c index ac05a928f764..b3c54be74556 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -105,7 +105,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) led_cdev->dev = device_create(leds_class, parent, 0, "%s", led_cdev->name); - if (unlikely(IS_ERR(led_cdev->dev))) + if (IS_ERR(led_cdev->dev)) return PTR_ERR(led_cdev->dev); dev_set_drvdata(led_cdev->dev, led_cdev); diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 2bc9bf7e88e5..8080249957af 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c @@ -85,27 +85,34 @@ static unsigned desc_size(const struct lguest_device_desc *desc) + desc->config_len; } -/* This tests (and acknowleges) a feature bit. */ -static bool lg_feature(struct virtio_device *vdev, unsigned fbit) +/* This gets the device's feature bits. */ +static u32 lg_get_features(struct virtio_device *vdev) { + unsigned int i; + u32 features = 0; struct lguest_device_desc *desc = to_lgdev(vdev)->desc; - u8 *features; - - /* Obviously if they ask for a feature off the end of our feature - * bitmap, it's not set. */ - if (fbit / 8 > desc->feature_len) - return false; - - /* The feature bitmap comes after the virtqueues. */ - features = lg_features(desc); - if (!(features[fbit / 8] & (1 << (fbit % 8)))) - return false; - - /* We set the matching bit in the other half of the bitmap to tell the - * Host we want to use this feature. We don't use this yet, but we - * could in future. */ - features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); - return true; + u8 *in_features = lg_features(desc); + + /* We do this the slow but generic way. */ + for (i = 0; i < min(desc->feature_len * 8, 32); i++) + if (in_features[i / 8] & (1 << (i % 8))) + features |= (1 << i); + + return features; +} + +static void lg_set_features(struct virtio_device *vdev, u32 features) +{ + unsigned int i; + struct lguest_device_desc *desc = to_lgdev(vdev)->desc; + /* Second half of bitmap is features we accept. */ + u8 *out_features = lg_features(desc) + desc->feature_len; + + memset(out_features, 0, desc->feature_len); + for (i = 0; i < min(desc->feature_len * 8, 32); i++) { + if (features & (1 << i)) + out_features[i / 8] |= (1 << (i % 8)); + } } /* Once they've found a field, getting a copy of it is easy. */ @@ -137,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev) return to_lgdev(vdev)->desc->status; } +/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the + * descriptor address of the device. A zero status means "reset". */ +static void set_status(struct virtio_device *vdev, u8 status) +{ + unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; + + /* We set the status. */ + to_lgdev(vdev)->desc->status = status; + hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); +} + static void lg_set_status(struct virtio_device *vdev, u8 status) { BUG_ON(!status); - to_lgdev(vdev)->desc->status = status; + set_status(vdev, status); } -/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor - * address of the device. The Host will zero the status and all the - * features. */ static void lg_reset(struct virtio_device *vdev) { - unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; - - hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); + set_status(vdev, 0); } /* @@ -286,7 +299,8 @@ static void lg_del_vq(struct virtqueue *vq) /* The ops structure which hooks everything together. */ static struct virtio_config_ops lguest_config_ops = { - .feature = lg_feature, + .get_features = lg_get_features, + .set_features = lg_set_features, .get = lg_get, .set = lg_set, .get_status = lg_get_status, diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 645e6e040bfb..e73a000473cc 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -102,7 +102,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) { /* We have a limited number the number of CPUs in the lguest struct. */ - if (id >= NR_CPUS) + if (id >= ARRAY_SIZE(cpu->lg->cpus)) return -EINVAL; /* Set up this CPU's id, and pointer back to the lguest struct. */ @@ -251,8 +251,6 @@ static ssize_t write(struct file *file, const char __user *in, if (!lg || (cpu_id >= lg->nr_cpus)) return -EINVAL; cpu = &lg->cpus[cpu_id]; - if (!cpu) - return -EINVAL; /* Once the Guest is dead, you can only read() why it died. */ if (lg->dead) diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 77f50b63a970..b52659620d50 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -234,6 +234,14 @@ config WINDFARM_PM112 which are the recent dual and quad G5 machines using the 970MP dual-core processor. +config WINDFARM_PM121 + tristate "Support for thermal management on PowerMac12,1" + depends on WINDFARM && I2C && PMAC_SMU + select I2C_POWERMAC + help + This driver provides thermal control for the PowerMac12,1 + which is the iMac G5 (iSight). + config ANSLCD tristate "Support for ANS LCD display" depends on ADB_CUDA && PPC_PMAC diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 2dfc3f4eaf42..e3132efa17c0 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \ windfarm_smu_sensors.o \ windfarm_max6690_sensor.o \ windfarm_lm75_sensor.o windfarm_pid.o +obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \ + windfarm_smu_controls.o \ + windfarm_smu_sensors.o \ + windfarm_max6690_sensor.o \ + windfarm_lm75_sensor.o windfarm_pid.o obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 7e10c3ab4d50..b92b959fe16e 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, */ if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) lm->sens.name = "hd-temp"; + else if (!strcmp(loc, "Incoming Air Temp")) + lm->sens.name = "incoming-air-temp"; + else if (!strcmp(loc, "ODD Temp")) + lm->sens.name = "optical-drive-temp"; + else if (!strcmp(loc, "HD Temp")) + lm->sens.name = "hard-drive-temp"; else goto fail; diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 5f03aab9fb5d..e207a90d6b27 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -77,18 +77,28 @@ static struct wf_sensor_ops wf_max6690_ops = { .owner = THIS_MODULE, }; -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr) +static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, + const char *loc) { struct wf_6690_sensor *max; - char *name = "backside-temp"; + char *name; max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); if (max == NULL) { printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " - "no memory\n", name); + "no memory\n", loc); return; } + if (!strcmp(loc, "BACKSIDE")) + name = "backside-temp"; + else if (!strcmp(loc, "NB Ambient")) + name = "north-bridge-temp"; + else if (!strcmp(loc, "GPU Ambient")) + name = "gpu-temp"; + else + goto fail; + max->sens.ops = &wf_max6690_ops; max->sens.name = name; max->i2c.addr = addr >> 1; @@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) if (loc == NULL || addr == 0) continue; printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); - if (strcmp(loc, "BACKSIDE")) - continue; - wf_max6690_create(adapter, addr); + wf_max6690_create(adapter, addr, loc); } return 0; diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c new file mode 100644 index 000000000000..66ec4fb115bb --- /dev/null +++ b/drivers/macintosh/windfarm_pm121.c @@ -0,0 +1,1040 @@ +/* + * Windfarm PowerMac thermal control. iMac G5 iSight + * + * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com> + * + * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin + * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org> + * + * Released under the term of the GNU GPL v2. + * + * + * + * PowerMac12,1 + * ============ + * + * + * The algorithm used is the PID control algorithm, used the same way + * the published Darwin code does, using the same values that are + * present in the Darwin 8.10 snapshot property lists (note however + * that none of the code has been re-used, it's a complete + * re-implementation + * + * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight + * 17" while Model 3 is iMac G5 20". They do have both the same + * controls with a tiny difference. The control-ids of hard-drive-fan + * and cpu-fan is swapped. + * + * + * Target Correction : + * + * controls have a target correction calculated as : + * + * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value + * new_value = max(new_value, max(new_min, 0)) + * + * OD Fan control correction. + * + * # model_id: 2 + * offset : -19563152 + * slope : 1956315 + * + * # model_id: 3 + * offset : -15650652 + * slope : 1565065 + * + * HD Fan control correction. + * + * # model_id: 2 + * offset : -15650652 + * slope : 1565065 + * + * # model_id: 3 + * offset : -19563152 + * slope : 1956315 + * + * CPU Fan control correction. + * + * # model_id: 2 + * offset : -25431900 + * slope : 2543190 + * + * # model_id: 3 + * offset : -15650652 + * slope : 1565065 + * + * + * Target rubber-banding : + * + * Some controls have a target correction which depends on another + * control value. The correction is computed in the following way : + * + * new_min = ref_value * slope + offset + * + * ref_value is the value of the reference control. If new_min is + * greater than 0, then we correct the target value using : + * + * new_target = max (new_target, new_min >> 16) + * + * + * # model_id : 2 + * control : cpu-fan + * ref : optical-drive-fan + * offset : -15650652 + * slope : 1565065 + * + * # model_id : 3 + * control : optical-drive-fan + * ref : hard-drive-fan + * offset : -32768000 + * slope : 65536 + * + * + * In order to have the moste efficient correction with those + * dependencies, we must trigger HD loop before OD loop before CPU + * loop. + * + * + * The various control loops found in Darwin config file are: + * + * HD Fan control loop. + * + * # model_id: 2 + * control : hard-drive-fan + * sensor : hard-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002D70A3 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x370000 + * Interval = 5s + * + * # model_id: 3 + * control : hard-drive-fan + * sensor : hard-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002170A3 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x370000 + * Interval = 5s + * + * OD Fan control loop. + * + * # model_id: 2 + * control : optical-drive-fan + * sensor : optical-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x001FAE14 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x320000 + * Interval = 5s + * + * # model_id: 3 + * control : optical-drive-fan + * sensor : optical-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x001FAE14 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x320000 + * Interval = 5s + * + * GPU Fan control loop. + * + * # model_id: 2 + * control : hard-drive-fan + * sensor : gpu-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002A6666 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x5A0000 + * Interval = 5s + * + * # model_id: 3 + * control : cpu-fan + * sensor : gpu-temp + * PID params : G_d = 0x00000000 + * G_p = 0x0010CCCC + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x500000 + * Interval = 5s + * + * KODIAK (aka northbridge) Fan control loop. + * + * # model_id: 2 + * control : optical-drive-fan + * sensor : north-bridge-temp + * PID params : G_d = 0x00000000 + * G_p = 0x003BD70A + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x550000 + * Interval = 5s + * + * # model_id: 3 + * control : hard-drive-fan + * sensor : north-bridge-temp + * PID params : G_d = 0x00000000 + * G_p = 0x0030F5C2 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x550000 + * Interval = 5s + * + * CPU Fan control loop. + * + * control : cpu-fan + * sensors : cpu-temp, cpu-power + * PID params : from SDB partition + * + * + * CPU Slew control loop. + * + * control : cpufreq-clamp + * sensor : cpu-temp + * + */ + +#undef DEBUG + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/kmod.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/sections.h> +#include <asm/smu.h> + +#include "windfarm.h" +#include "windfarm_pid.h" + +#define VERSION "0.3" + +static int pm121_mach_model; /* machine model id */ + +/* Controls & sensors */ +static struct wf_sensor *sensor_cpu_power; +static struct wf_sensor *sensor_cpu_temp; +static struct wf_sensor *sensor_cpu_voltage; +static struct wf_sensor *sensor_cpu_current; +static struct wf_sensor *sensor_gpu_temp; +static struct wf_sensor *sensor_north_bridge_temp; +static struct wf_sensor *sensor_hard_drive_temp; +static struct wf_sensor *sensor_optical_drive_temp; +static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */ + +enum { + FAN_CPU, + FAN_HD, + FAN_OD, + CPUFREQ, + N_CONTROLS +}; +static struct wf_control *controls[N_CONTROLS] = {}; + +/* Set to kick the control loop into life */ +static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started; + +enum { + FAILURE_FAN = 1 << 0, + FAILURE_SENSOR = 1 << 1, + FAILURE_OVERTEMP = 1 << 2 +}; + +/* All sys loops. Note the HD before the OD loop in order to have it + run before. */ +enum { + LOOP_GPU, /* control = hd or cpu, but luckily, + it doesn't matter */ + LOOP_HD, /* control = hd */ + LOOP_KODIAK, /* control = hd or od */ + LOOP_OD, /* control = od */ + N_LOOPS +}; + +static const char *loop_names[N_LOOPS] = { + "GPU", + "HD", + "KODIAK", + "OD", +}; + +#define PM121_NUM_CONFIGS 2 + +static unsigned int pm121_failure_state; +static int pm121_readjust, pm121_skipping; +static s32 average_power; + +struct pm121_correction { + int offset; + int slope; +}; + +static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = { + /* FAN_OD */ + { + /* MODEL 2 */ + { .offset = -19563152, + .slope = 1956315 + }, + /* MODEL 3 */ + { .offset = -15650652, + .slope = 1565065 + }, + }, + /* FAN_HD */ + { + /* MODEL 2 */ + { .offset = -15650652, + .slope = 1565065 + }, + /* MODEL 3 */ + { .offset = -19563152, + .slope = 1956315 + }, + }, + /* FAN_CPU */ + { + /* MODEL 2 */ + { .offset = -25431900, + .slope = 2543190 + }, + /* MODEL 3 */ + { .offset = -15650652, + .slope = 1565065 + }, + }, + /* CPUFREQ has no correction (and is not implemented at all) */ +}; + +struct pm121_connection { + unsigned int control_id; + unsigned int ref_id; + struct pm121_correction correction; +}; + +static struct pm121_connection pm121_connections[] = { + /* MODEL 2 */ + { .control_id = FAN_CPU, + .ref_id = FAN_OD, + { .offset = -32768000, + .slope = 65536 + } + }, + /* MODEL 3 */ + { .control_id = FAN_OD, + .ref_id = FAN_HD, + { .offset = -32768000, + .slope = 65536 + } + }, +}; + +/* pointer to the current model connection */ +static struct pm121_connection *pm121_connection; + +/* + * ****** System Fans Control Loop ****** + * + */ + +/* Since each loop handles only one control and we want to avoid + * writing virtual control, we store the control correction with the + * loop params. Some data are not set, there are common to all loop + * and thus, hardcoded. + */ +struct pm121_sys_param { + /* purely informative since we use mach_model-2 as index */ + int model_id; + struct wf_sensor **sensor; /* use sensor_id instead ? */ + s32 gp, itarget; + unsigned int control_id; +}; + +static struct pm121_sys_param +pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = { + /* GPU Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_gpu_temp, + .gp = 0x002A6666, + .itarget = 0x5A0000, + .control_id = FAN_HD, + }, + { .model_id = 3, + .sensor = &sensor_gpu_temp, + .gp = 0x0010CCCC, + .itarget = 0x500000, + .control_id = FAN_CPU, + }, + }, + /* HD Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_hard_drive_temp, + .gp = 0x002D70A3, + .itarget = 0x370000, + .control_id = FAN_HD, + }, + { .model_id = 3, + .sensor = &sensor_hard_drive_temp, + .gp = 0x002170A3, + .itarget = 0x370000, + .control_id = FAN_HD, + }, + }, + /* KODIAK Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_north_bridge_temp, + .gp = 0x003BD70A, + .itarget = 0x550000, + .control_id = FAN_OD, + }, + { .model_id = 3, + .sensor = &sensor_north_bridge_temp, + .gp = 0x0030F5C2, + .itarget = 0x550000, + .control_id = FAN_HD, + }, + }, + /* OD Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_optical_drive_temp, + .gp = 0x001FAE14, + .itarget = 0x320000, + .control_id = FAN_OD, + }, + { .model_id = 3, + .sensor = &sensor_optical_drive_temp, + .gp = 0x001FAE14, + .itarget = 0x320000, + .control_id = FAN_OD, + }, + }, +}; + +/* the hardcoded values */ +#define PM121_SYS_GD 0x00000000 +#define PM121_SYS_GR 0x00019999 +#define PM121_SYS_HISTORY_SIZE 2 +#define PM121_SYS_INTERVAL 5 + +/* State data used by the system fans control loop + */ +struct pm121_sys_state { + int ticks; + s32 setpoint; + struct wf_pid_state pid; +}; + +struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {}; + +/* + * ****** CPU Fans Control Loop ****** + * + */ + +#define PM121_CPU_INTERVAL 1 + +/* State data used by the cpu fans control loop + */ +struct pm121_cpu_state { + int ticks; + s32 setpoint; + struct wf_cpu_pid_state pid; +}; + +static struct pm121_cpu_state *pm121_cpu_state; + + + +/* + * ***** Implementation ***** + * + */ + +/* correction the value using the output-low-bound correction algo */ +static s32 pm121_correct(s32 new_setpoint, + unsigned int control_id, + s32 min) +{ + s32 new_min; + struct pm121_correction *correction; + correction = &corrections[control_id][pm121_mach_model - 2]; + + new_min = (average_power * correction->slope) >> 16; + new_min += correction->offset; + new_min = (new_min >> 16) + min; + + return max(new_setpoint, max(new_min, 0)); +} + +static s32 pm121_connect(unsigned int control_id, s32 setpoint) +{ + s32 new_min, value, new_setpoint; + + if (pm121_connection->control_id == control_id) { + controls[control_id]->ops->get_value(controls[control_id], + &value); + new_min = value * pm121_connection->correction.slope; + new_min += pm121_connection->correction.offset; + if (new_min > 0) { + new_setpoint = max(setpoint, (new_min >> 16)); + if (new_setpoint != setpoint) { + pr_debug("pm121: %s depending on %s, " + "corrected from %d to %d RPM\n", + controls[control_id]->name, + controls[pm121_connection->ref_id]->name, + (int) setpoint, (int) new_setpoint); + } + } else + new_setpoint = setpoint; + } + /* no connection */ + else + new_setpoint = setpoint; + + return new_setpoint; +} + +/* FAN LOOPS */ +static void pm121_create_sys_fans(int loop_id) +{ + struct pm121_sys_param *param = NULL; + struct wf_pid_param pid_param; + struct wf_control *control = NULL; + int i; + + /* First, locate the params for this model */ + for (i = 0; i < PM121_NUM_CONFIGS; i++) { + if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) { + param = &(pm121_sys_all_params[loop_id][i]); + break; + } + } + + /* No params found, put fans to max */ + if (param == NULL) { + printk(KERN_WARNING "pm121: %s fan config not found " + " for this machine model\n", + loop_names[loop_id]); + goto fail; + } + + control = controls[param->control_id]; + + /* Alloc & initialize state */ + pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state), + GFP_KERNEL); + if (pm121_sys_state[loop_id] == NULL) { + printk(KERN_WARNING "pm121: Memory allocation error\n"); + goto fail; + } + pm121_sys_state[loop_id]->ticks = 1; + + /* Fill PID params */ + pid_param.gd = PM121_SYS_GD; + pid_param.gp = param->gp; + pid_param.gr = PM121_SYS_GR; + pid_param.interval = PM121_SYS_INTERVAL; + pid_param.history_len = PM121_SYS_HISTORY_SIZE; + pid_param.itarget = param->itarget; + pid_param.min = control->ops->get_min(control); + pid_param.max = control->ops->get_max(control); + + wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param); + + pr_debug("pm121: %s Fan control loop initialized.\n" + " itarged=%d.%03d, min=%d RPM, max=%d RPM\n", + loop_names[loop_id], FIX32TOPRINT(pid_param.itarget), + pid_param.min, pid_param.max); + return; + + fail: + /* note that this is not optimal since another loop may still + control the same control */ + printk(KERN_WARNING "pm121: failed to set up %s loop " + "setting \"%s\" to max speed.\n", + loop_names[loop_id], control->name); + + if (control) + wf_control_set_max(control); +} + +static void pm121_sys_fans_tick(int loop_id) +{ + struct pm121_sys_param *param; + struct pm121_sys_state *st; + struct wf_sensor *sensor; + struct wf_control *control; + s32 temp, new_setpoint; + int rc; + + param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]); + st = pm121_sys_state[loop_id]; + sensor = *(param->sensor); + control = controls[param->control_id]; + + if (--st->ticks != 0) { + if (pm121_readjust) + goto readjust; + return; + } + st->ticks = PM121_SYS_INTERVAL; + + rc = sensor->ops->get_value(sensor, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: %s sensor error %d\n", + sensor->name, rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n", + loop_names[loop_id], sensor->name, + FIX32TOPRINT(temp)); + + new_setpoint = wf_pid_run(&st->pid, temp); + + /* correction */ + new_setpoint = pm121_correct(new_setpoint, + param->control_id, + st->pid.param.min); + /* linked corretion */ + new_setpoint = pm121_connect(param->control_id, new_setpoint); + + if (new_setpoint == st->setpoint) + return; + st->setpoint = new_setpoint; + pr_debug("pm121: %s corrected setpoint: %d RPM\n", + control->name, (int)new_setpoint); + readjust: + if (control && pm121_failure_state == 0) { + rc = control->ops->set_value(control, st->setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: %s fan error %d\n", + control->name, rc); + pm121_failure_state |= FAILURE_FAN; + } + } +} + + +/* CPU LOOP */ +static void pm121_create_cpu_fans(void) +{ + struct wf_cpu_pid_param pid_param; + const struct smu_sdbp_header *hdr; + struct smu_sdbp_cpupiddata *piddata; + struct smu_sdbp_fvt *fvt; + struct wf_control *fan_cpu; + s32 tmax, tdelta, maxpow, powadj; + + fan_cpu = controls[FAN_CPU]; + + /* First, locate the PID params in SMU SBD */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); + if (hdr == 0) { + printk(KERN_WARNING "pm121: CPU PID fan config not found.\n"); + goto fail; + } + piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; + + /* Get the FVT params for operating point 0 (the only supported one + * for now) in order to get tmax + */ + hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (hdr) { + fvt = (struct smu_sdbp_fvt *)&hdr[1]; + tmax = ((s32)fvt->maxtemp) << 16; + } else + tmax = 0x5e0000; /* 94 degree default */ + + /* Alloc & initialize state */ + pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state), + GFP_KERNEL); + if (pm121_cpu_state == NULL) + goto fail; + pm121_cpu_state->ticks = 1; + + /* Fill PID params */ + pid_param.interval = PM121_CPU_INTERVAL; + pid_param.history_len = piddata->history_len; + if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { + printk(KERN_WARNING "pm121: History size overflow on " + "CPU control loop (%d)\n", piddata->history_len); + pid_param.history_len = WF_CPU_PID_MAX_HISTORY; + } + pid_param.gd = piddata->gd; + pid_param.gp = piddata->gp; + pid_param.gr = piddata->gr / pid_param.history_len; + + tdelta = ((s32)piddata->target_temp_delta) << 16; + maxpow = ((s32)piddata->max_power) << 16; + powadj = ((s32)piddata->power_adj) << 16; + + pid_param.tmax = tmax; + pid_param.ttarget = tmax - tdelta; + pid_param.pmaxadj = maxpow - powadj; + + pid_param.min = fan_cpu->ops->get_min(fan_cpu); + pid_param.max = fan_cpu->ops->get_max(fan_cpu); + + wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param); + + pr_debug("pm121: CPU Fan control initialized.\n"); + pr_debug(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n", + FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), + pid_param.min, pid_param.max); + + return; + + fail: + printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n"); + + if (controls[CPUFREQ]) + wf_control_set_max(controls[CPUFREQ]); + if (fan_cpu) + wf_control_set_max(fan_cpu); +} + + +static void pm121_cpu_fans_tick(struct pm121_cpu_state *st) +{ + s32 new_setpoint, temp, power; + struct wf_control *fan_cpu = NULL; + int rc; + + if (--st->ticks != 0) { + if (pm121_readjust) + goto readjust; + return; + } + st->ticks = PM121_CPU_INTERVAL; + + fan_cpu = controls[FAN_CPU]; + + rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); + if (rc) { + printk(KERN_WARNING "pm121: CPU temp sensor error %d\n", + rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); + if (rc) { + printk(KERN_WARNING "pm121: CPU power sensor error %d\n", + rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n", + FIX32TOPRINT(temp), FIX32TOPRINT(power)); + + if (temp > st->pid.param.tmax) + pm121_failure_state |= FAILURE_OVERTEMP; + + new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); + + /* correction */ + new_setpoint = pm121_correct(new_setpoint, + FAN_CPU, + st->pid.param.min); + + /* connected correction */ + new_setpoint = pm121_connect(FAN_CPU, new_setpoint); + + if (st->setpoint == new_setpoint) + return; + st->setpoint = new_setpoint; + pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint); + + readjust: + if (fan_cpu && pm121_failure_state == 0) { + rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint); + if (rc) { + printk(KERN_WARNING "pm121: %s fan error %d\n", + fan_cpu->name, rc); + pm121_failure_state |= FAILURE_FAN; + } + } +} + +/* + * ****** Common ****** + * + */ + +static void pm121_tick(void) +{ + unsigned int last_failure = pm121_failure_state; + unsigned int new_failure; + s32 total_power; + int i; + + if (!pm121_started) { + pr_debug("pm121: creating control loops !\n"); + for (i = 0; i < N_LOOPS; i++) + pm121_create_sys_fans(i); + + pm121_create_cpu_fans(); + pm121_started = 1; + } + + /* skipping ticks */ + if (pm121_skipping && --pm121_skipping) + return; + + /* compute average power */ + total_power = 0; + for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++) + total_power += pm121_cpu_state->pid.powers[i]; + + average_power = total_power / pm121_cpu_state->pid.param.history_len; + + + pm121_failure_state = 0; + for (i = 0 ; i < N_LOOPS; i++) { + if (pm121_sys_state[i]) + pm121_sys_fans_tick(i); + } + + if (pm121_cpu_state) + pm121_cpu_fans_tick(pm121_cpu_state); + + pm121_readjust = 0; + new_failure = pm121_failure_state & ~last_failure; + + /* If entering failure mode, clamp cpufreq and ramp all + * fans to full speed. + */ + if (pm121_failure_state && !last_failure) { + for (i = 0; i < N_CONTROLS; i++) { + if (controls[i]) + wf_control_set_max(controls[i]); + } + } + + /* If leaving failure mode, unclamp cpufreq and readjust + * all fans on next iteration + */ + if (!pm121_failure_state && last_failure) { + if (controls[CPUFREQ]) + wf_control_set_min(controls[CPUFREQ]); + pm121_readjust = 1; + } + + /* Overtemp condition detected, notify and start skipping a couple + * ticks to let the temperature go down + */ + if (new_failure & FAILURE_OVERTEMP) { + wf_set_overtemp(); + pm121_skipping = 2; + } + + /* We only clear the overtemp condition if overtemp is cleared + * _and_ no other failure is present. Since a sensor error will + * clear the overtemp condition (can't measure temperature) at + * the control loop levels, but we don't want to keep it clear + * here in this case + */ + if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) + wf_clear_overtemp(); +} + + +static struct wf_control* pm121_register_control(struct wf_control *ct, + const char *match, + unsigned int id) +{ + if (controls[id] == NULL && !strcmp(ct->name, match)) { + if (wf_get_control(ct) == 0) + controls[id] = ct; + } + return controls[id]; +} + +static void pm121_new_control(struct wf_control *ct) +{ + int all = 1; + + if (pm121_all_controls_ok) + return; + + all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all; + all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all; + all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all; + all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all; + + if (all) + pm121_all_controls_ok = 1; +} + + + + +static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor, + const char *match, + struct wf_sensor **var) +{ + if (*var == NULL && !strcmp(sensor->name, match)) { + if (wf_get_sensor(sensor) == 0) + *var = sensor; + } + return *var; +} + +static void pm121_new_sensor(struct wf_sensor *sr) +{ + int all = 1; + + if (pm121_all_sensors_ok) + return; + + all = pm121_register_sensor(sr, "cpu-temp", + &sensor_cpu_temp) && all; + all = pm121_register_sensor(sr, "cpu-current", + &sensor_cpu_current) && all; + all = pm121_register_sensor(sr, "cpu-voltage", + &sensor_cpu_voltage) && all; + all = pm121_register_sensor(sr, "cpu-power", + &sensor_cpu_power) && all; + all = pm121_register_sensor(sr, "hard-drive-temp", + &sensor_hard_drive_temp) && all; + all = pm121_register_sensor(sr, "optical-drive-temp", + &sensor_optical_drive_temp) && all; + all = pm121_register_sensor(sr, "incoming-air-temp", + &sensor_incoming_air_temp) && all; + all = pm121_register_sensor(sr, "north-bridge-temp", + &sensor_north_bridge_temp) && all; + all = pm121_register_sensor(sr, "gpu-temp", + &sensor_gpu_temp) && all; + + if (all) + pm121_all_sensors_ok = 1; +} + + + +static int pm121_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + switch (event) { + case WF_EVENT_NEW_CONTROL: + pr_debug("pm121: new control %s detected\n", + ((struct wf_control *)data)->name); + pm121_new_control(data); + break; + case WF_EVENT_NEW_SENSOR: + pr_debug("pm121: new sensor %s detected\n", + ((struct wf_sensor *)data)->name); + pm121_new_sensor(data); + break; + case WF_EVENT_TICK: + if (pm121_all_controls_ok && pm121_all_sensors_ok) + pm121_tick(); + break; + } + + return 0; +} + +static struct notifier_block pm121_events = { + .notifier_call = pm121_notify, +}; + +static int pm121_init_pm(void) +{ + const struct smu_sdbp_header *hdr; + + hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL); + if (hdr != 0) { + struct smu_sdbp_sensortree *st = + (struct smu_sdbp_sensortree *)&hdr[1]; + pm121_mach_model = st->model_id; + } + + pm121_connection = &pm121_connections[pm121_mach_model - 2]; + + printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n", + pm121_mach_model); + + return 0; +} + + +static int pm121_probe(struct platform_device *ddev) +{ + wf_register_client(&pm121_events); + + return 0; +} + +static int __devexit pm121_remove(struct platform_device *ddev) +{ + wf_unregister_client(&pm121_events); + return 0; +} + +static struct platform_driver pm121_driver = { + .probe = pm121_probe, + .remove = __devexit_p(pm121_remove), + .driver = { + .name = "windfarm", + .bus = &platform_bus_type, + }, +}; + + +static int __init pm121_init(void) +{ + int rc = -ENODEV; + + if (machine_is_compatible("PowerMac12,1")) + rc = pm121_init_pm(); + + if (rc == 0) { + request_module("windfarm_smu_controls"); + request_module("windfarm_smu_sensors"); + request_module("windfarm_smu_sat"); + request_module("windfarm_lm75_sensor"); + request_module("windfarm_max6690_sensor"); + request_module("windfarm_cpufreq_clamp"); + platform_driver_register(&pm121_driver); + } + + return rc; +} + +static void __exit pm121_exit(void) +{ + + platform_driver_unregister(&pm121_driver); +} + + +module_init(pm121_init); +module_exit(pm121_exit); + +MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>"); +MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 58c2590f05ec..961fa0e7c2cf 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, fct->ctrl.name = "cpu-fan"; else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive")) fct->ctrl.name = "drive-bay-fan"; + else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */ + fct->ctrl.name = "hard-drive-fan"; + else if (!strcmp(l, "ODD Fan")) /* same */ + fct->ctrl.name = "optical-drive-fan"; /* Unrecognized fan, bail out */ if (fct->ctrl.name == NULL) diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c index 0c7bfa74c8ef..494f0c2001f5 100644 --- a/drivers/mca/mca-legacy.c +++ b/drivers/mca/mca-legacy.c @@ -282,24 +282,6 @@ void mca_set_adapter_name(int slot, char* name) EXPORT_SYMBOL(mca_set_adapter_name); /** - * mca_is_adapter_used - check if claimed by driver - * @slot: slot to check - * - * Returns 1 if the slot has been claimed by a driver - */ - -int mca_is_adapter_used(int slot) -{ - struct mca_device *mca_dev = mca_find_device_by_slot(slot); - - if(!mca_dev) - return 0; - - return mca_device_claimed(mca_dev); -} -EXPORT_SYMBOL(mca_is_adapter_used); - -/** * mca_mark_as_used - claim an MCA device * @slot: slot to claim * FIXME: should we make this threadsafe diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c index 33d5e0820cc5..81ea0d377bf4 100644 --- a/drivers/mca/mca-proc.c +++ b/drivers/mca/mca-proc.c @@ -183,7 +183,7 @@ void __init mca_do_proc_init(void) struct proc_dir_entry* node = NULL; struct mca_device *mca_dev; - proc_mca = proc_mkdir("mca", &proc_root); + proc_mca = proc_mkdir("mca", NULL); create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL); create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL); diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 6b91b9ab1d41..3ea5ad4b7805 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -110,8 +110,6 @@ static struct request *get_failover_req(struct emc_handler *h, memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; - memset(&rq->cmd, 0, BLK_MAX_CDB); - rq->timeout = EMC_FAILOVER_TIMEOUT; rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c index 204bf42c9449..b63a0ab37c53 100644 --- a/drivers/md/dm-mpath-hp-sw.c +++ b/drivers/md/dm-mpath-hp-sw.c @@ -137,7 +137,6 @@ static struct request *hp_sw_get_request(struct dm_path *path) req->sense = h->sense; memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - memset(&req->cmd, 0, BLK_MAX_CDB); req->cmd[0] = START_STOP; req->cmd[4] = 1; req->cmd_len = COMMAND_SIZE(req->cmd[0]); diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c index e04eb5c697fb..95e77734880a 100644 --- a/drivers/md/dm-mpath-rdac.c +++ b/drivers/md/dm-mpath-rdac.c @@ -284,7 +284,6 @@ static struct request *get_rdac_req(struct rdac_handler *h, return NULL; } - memset(&rq->cmd, 0, BLK_MAX_CDB); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 51be53344214..94116eaf4709 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -873,10 +873,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) q->max_hw_sectors = t->limits.max_hw_sectors; q->seg_boundary_mask = t->limits.seg_boundary_mask; q->bounce_pfn = t->limits.bounce_pfn; + if (t->limits.no_cluster) - q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER); + queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); else - q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER); + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); } diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c index 50377e5dc2a3..6f65883aef12 100644 --- a/drivers/md/dm-uevent.c +++ b/drivers/md/dm-uevent.c @@ -78,7 +78,7 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md, event = dm_uevent_alloc(md); if (!event) { - DMERR("%s: dm_uevent_alloc() failed", __FUNCTION__); + DMERR("%s: dm_uevent_alloc() failed", __func__); goto err_nomem; } @@ -86,32 +86,32 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md, if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) { DMERR("%s: add_uevent_var() for DM_TARGET failed", - __FUNCTION__); + __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) { DMERR("%s: add_uevent_var() for DM_ACTION failed", - __FUNCTION__); + __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u", dm_next_uevent_seq(md))) { DMERR("%s: add_uevent_var() for DM_SEQNUM failed", - __FUNCTION__); + __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) { - DMERR("%s: add_uevent_var() for DM_PATH failed", __FUNCTION__); + DMERR("%s: add_uevent_var() for DM_PATH failed", __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d", nr_valid_paths)) { DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed", - __FUNCTION__); + __func__); goto err_add; } @@ -146,25 +146,25 @@ void dm_send_uevents(struct list_head *events, struct kobject *kobj) if (dm_copy_name_and_uuid(event->md, event->name, event->uuid)) { DMERR("%s: dm_copy_name_and_uuid() failed", - __FUNCTION__); + __func__); goto uevent_free; } if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) { DMERR("%s: add_uevent_var() for DM_NAME failed", - __FUNCTION__); + __func__); goto uevent_free; } if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) { DMERR("%s: add_uevent_var() for DM_UUID failed", - __FUNCTION__); + __func__); goto uevent_free; } r = kobject_uevent_env(kobj, event->action, event->ku_env.envp); if (r) - DMERR("%s: kobject_uevent_env failed", __FUNCTION__); + DMERR("%s: kobject_uevent_env failed", __func__); uevent_free: dm_uevent_free(event); } @@ -187,7 +187,7 @@ void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti, struct dm_uevent *event; if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) { - DMERR("%s: Invalid event_type %d", __FUNCTION__, event_type); + DMERR("%s: Invalid event_type %d", __func__, event_type); goto out; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 5ebfb4d79901..83eb78b00137 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -276,13 +276,15 @@ 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) { kfree(new); return NULL; } - set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags); + /* Can be unlocked because the queue is new: no concurrency */ + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue); blk_queue_make_request(new->queue, md_fail_request); @@ -731,9 +733,9 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version else rdev->desc_nr = sb->this_disk.number; - if (refdev == 0) + if (!refdev) { ret = 1; - else { + } else { __u64 ev1, ev2; mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page); if (!uuid_equal(refsb, sb)) { @@ -1116,9 +1118,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) else rdev->desc_nr = le32_to_cpu(sb->dev_number); - if (refdev == 0) + if (!refdev) { ret = 1; - else { + } else { __u64 ev1, ev2; struct mdp_superblock_1 *refsb = (struct mdp_superblock_1*)page_address(refdev->sb_page); @@ -1368,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) { @@ -1651,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); @@ -1819,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); @@ -1835,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) { @@ -1857,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; } @@ -2096,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; } @@ -2185,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; @@ -2456,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); @@ -2590,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); @@ -2611,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); @@ -2634,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; @@ -3711,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", @@ -4918,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), @@ -5364,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) { @@ -5718,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) { @@ -5788,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; @@ -5800,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) )) @@ -5809,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); @@ -5913,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) { @@ -5947,13 +6024,9 @@ static struct notifier_block md_notifier = { static void md_geninit(void) { - struct proc_dir_entry *p; - dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); - p = create_proc_entry("mdstat", S_IRUGO, NULL); - if (p) - p->proc_fops = &md_seq_fops; + proc_create("mdstat", S_IRUGO, NULL, &md_seq_fops); } static int __init md_init(void) diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 3f299d835a2b..42ee1a2dc144 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -244,7 +244,8 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) conf->working_disks--; mddev->degraded++; printk(KERN_ALERT "multipath: IO failure on %s," - " disabling IO path. \n Operation continuing" + " disabling IO path.\n" + "multipath: Operation continuing" " on %d IO paths.\n", bdevname (rdev->bdev,b), conf->working_disks); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ff61b309129a..6778b7cb39bd 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) { @@ -1008,8 +1029,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } else set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); - printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" - " Operation continuing on %d devices\n", + printk(KERN_ALERT "raid1: Disk failure on %s, disabling device.\n" + "raid1: Operation continuing on %d devices.\n", bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 32389d2f18fc..5938fa962922 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); @@ -1001,8 +1024,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); - printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" - " Operation continuing on %d devices\n", + printk(KERN_ALERT "raid10: Disk failure on %s, disabling device.\n" + "raid10: Operation continuing on %d devices.\n", bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b162b839a662..087eee0cb809 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -63,6 +63,7 @@ #define STRIPE_SHIFT (PAGE_SHIFT - 9) #define STRIPE_SECTORS (STRIPE_SIZE>>9) #define IO_THRESHOLD 1 +#define BYPASS_THRESHOLD 1 #define NR_HASH (PAGE_SIZE / sizeof(struct hlist_head)) #define HASH_MASK (NR_HASH - 1) @@ -398,6 +399,7 @@ static void ops_run_io(struct stripe_head *sh) might_sleep(); + set_bit(STRIPE_IO_STARTED, &sh->state); for (i = disks; i--; ) { int rw; struct bio *bi; @@ -433,7 +435,7 @@ static void ops_run_io(struct stripe_head *sh) bi->bi_bdev = rdev->bdev; pr_debug("%s: for %llu schedule op %ld on disc %d\n", - __FUNCTION__, (unsigned long long)sh->sector, + __func__, (unsigned long long)sh->sector, bi->bi_rw, i); atomic_inc(&sh->count); bi->bi_sector = sh->sector + rdev->data_offset; @@ -520,7 +522,7 @@ static void ops_complete_biofill(void *stripe_head_ref) raid5_conf_t *conf = sh->raid_conf; int i; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); /* clear completed biofills */ @@ -569,7 +571,7 @@ static void ops_run_biofill(struct stripe_head *sh) raid5_conf_t *conf = sh->raid_conf; int i; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = sh->disks; i--; ) { @@ -600,7 +602,7 @@ static void ops_complete_compute5(void *stripe_head_ref) int target = sh->ops.target; struct r5dev *tgt = &sh->dev[target]; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); set_bit(R5_UPTODATE, &tgt->flags); @@ -625,7 +627,7 @@ ops_run_compute5(struct stripe_head *sh, unsigned long pending) int i; pr_debug("%s: stripe %llu block: %d\n", - __FUNCTION__, (unsigned long long)sh->sector, target); + __func__, (unsigned long long)sh->sector, target); BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags)); for (i = disks; i--; ) @@ -653,7 +655,7 @@ static void ops_complete_prexor(void *stripe_head_ref) { struct stripe_head *sh = stripe_head_ref; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); set_bit(STRIPE_OP_PREXOR, &sh->ops.complete); @@ -670,7 +672,7 @@ ops_run_prexor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) /* existing parity data subtracted */ struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -699,7 +701,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx, */ int prexor = test_bit(STRIPE_OP_PREXOR, &pending); - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -744,7 +746,7 @@ static void ops_complete_postxor(void *stripe_head_ref) { struct stripe_head *sh = stripe_head_ref; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); set_bit(STRIPE_OP_POSTXOR, &sh->ops.complete); @@ -757,7 +759,7 @@ static void ops_complete_write(void *stripe_head_ref) struct stripe_head *sh = stripe_head_ref; int disks = sh->disks, i, pd_idx = sh->pd_idx; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -787,7 +789,7 @@ ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx, unsigned long flags; dma_async_tx_callback callback; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); /* check if prexor is active which means only process blocks @@ -837,7 +839,7 @@ static void ops_complete_check(void *stripe_head_ref) struct stripe_head *sh = stripe_head_ref; int pd_idx = sh->pd_idx; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); if (test_and_clear_bit(STRIPE_OP_MOD_DMA_CHECK, &sh->ops.pending) && @@ -859,7 +861,7 @@ static void ops_run_check(struct stripe_head *sh) int count = 0, pd_idx = sh->pd_idx, i; struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -1260,8 +1262,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } set_bit(Faulty, &rdev->flags); printk (KERN_ALERT - "raid5: Disk failure on %s, disabling device." - " Operation continuing on %d devices\n", + "raid5: Disk failure on %s, disabling device.\n" + "raid5: Operation continuing on %d devices.\n", bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } } @@ -1720,6 +1722,9 @@ handle_write_operations5(struct stripe_head *sh, int rcw, int expand) locked++; } } + if (locked + 1 == disks) + if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) + atomic_inc(&sh->raid_conf->pending_full_writes); } else { BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) || test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags))); @@ -1759,7 +1764,7 @@ handle_write_operations5(struct stripe_head *sh, int rcw, int expand) locked++; pr_debug("%s: stripe %llu locked: %d pending: %lx\n", - __FUNCTION__, (unsigned long long)sh->sector, + __func__, (unsigned long long)sh->sector, locked, sh->ops.pending); return locked; @@ -1947,6 +1952,9 @@ handle_requests_to_failed_array(raid5_conf_t *conf, struct stripe_head *sh, STRIPE_SECTORS, 0, 0); } + if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) + if (atomic_dec_and_test(&conf->pending_full_writes)) + md_wakeup_thread(conf->mddev->thread); } /* __handle_issuing_new_read_requests5 - returns 0 if there are no more disks @@ -2149,6 +2157,10 @@ static void handle_completed_write_requests(raid5_conf_t *conf, 0); } } + + if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) + if (atomic_dec_and_test(&conf->pending_full_writes)) + md_wakeup_thread(conf->mddev->thread); } static void handle_issuing_new_write_requests5(raid5_conf_t *conf, @@ -2333,6 +2345,9 @@ static void handle_issuing_new_write_requests6(raid5_conf_t *conf, s->locked++; set_bit(R5_Wantwrite, &sh->dev[i].flags); } + if (s->locked == disks) + if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) + atomic_inc(&conf->pending_full_writes); /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */ set_bit(STRIPE_INSYNC, &sh->state); @@ -2592,6 +2607,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, } } + /* * handle_stripe - do things to a stripe. * @@ -2617,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 " @@ -2676,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); @@ -2690,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++; @@ -2879,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); @@ -2897,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, " @@ -2960,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); @@ -2974,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, @@ -3079,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-- ;) { @@ -3094,6 +3142,8 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) else continue; + set_bit(STRIPE_IO_STARTED, &sh->state); + bi = &sh->dev[i].req; bi->bi_rw = rw; @@ -3164,7 +3214,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf) clear_bit(STRIPE_DELAYED, &sh->state); if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) atomic_inc(&conf->preread_active_stripes); - list_add_tail(&sh->lru, &conf->handle_list); + list_add_tail(&sh->lru, &conf->hold_list); } } else blk_plug_device(conf->mddev->queue); @@ -3442,6 +3492,58 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio) } } +/* __get_priority_stripe - get the next stripe to process + * + * Full stripe writes are allowed to pass preread active stripes up until + * the bypass_threshold is exceeded. In general the bypass_count + * increments when the handle_list is handled before the hold_list; however, it + * will not be incremented when STRIPE_IO_STARTED is sampled set signifying a + * stripe with in flight i/o. The bypass_count will be reset when the + * head of the hold_list has changed, i.e. the head was promoted to the + * handle_list. + */ +static struct stripe_head *__get_priority_stripe(raid5_conf_t *conf) +{ + struct stripe_head *sh; + + pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n", + __func__, + list_empty(&conf->handle_list) ? "empty" : "busy", + list_empty(&conf->hold_list) ? "empty" : "busy", + atomic_read(&conf->pending_full_writes), conf->bypass_count); + + if (!list_empty(&conf->handle_list)) { + sh = list_entry(conf->handle_list.next, typeof(*sh), lru); + + if (list_empty(&conf->hold_list)) + conf->bypass_count = 0; + else if (!test_bit(STRIPE_IO_STARTED, &sh->state)) { + if (conf->hold_list.next == conf->last_hold) + conf->bypass_count++; + else { + conf->last_hold = conf->hold_list.next; + conf->bypass_count -= conf->bypass_threshold; + if (conf->bypass_count < 0) + conf->bypass_count = 0; + } + } + } else if (!list_empty(&conf->hold_list) && + ((conf->bypass_threshold && + conf->bypass_count > conf->bypass_threshold) || + atomic_read(&conf->pending_full_writes) == 0)) { + sh = list_entry(conf->hold_list.next, + typeof(*sh), lru); + conf->bypass_count -= conf->bypass_threshold; + if (conf->bypass_count < 0) + conf->bypass_count = 0; + } else + return NULL; + + list_del_init(&sh->lru); + atomic_inc(&sh->count); + BUG_ON(atomic_read(&sh->count) != 1); + return sh; +} static int make_request(struct request_queue *q, struct bio * bi) { @@ -3914,7 +4016,6 @@ static void raid5d(mddev_t *mddev) handled = 0; spin_lock_irq(&conf->device_lock); while (1) { - struct list_head *first; struct bio *bio; if (conf->seq_flush != conf->seq_write) { @@ -3936,17 +4037,12 @@ static void raid5d(mddev_t *mddev) handled++; } - if (list_empty(&conf->handle_list)) { + sh = __get_priority_stripe(conf); + + if (!sh) { async_tx_issue_pending_all(); break; } - - first = conf->handle_list.next; - sh = list_entry(first, struct stripe_head, lru); - - list_del_init(first); - atomic_inc(&sh->count); - BUG_ON(atomic_read(&sh->count)!= 1); spin_unlock_irq(&conf->device_lock); handled++; @@ -3978,15 +4074,13 @@ static ssize_t raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) { raid5_conf_t *conf = mddev_to_conf(mddev); - char *end; - int new; + unsigned long new; if (len >= PAGE_SIZE) return -EINVAL; if (!conf) return -ENODEV; - new = simple_strtoul(page, &end, 10); - if (!*page || (*end && *end != '\n') ) + if (strict_strtoul(page, 10, &new)) return -EINVAL; if (new <= 16 || new > 32768) return -EINVAL; @@ -4011,6 +4105,40 @@ raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, raid5_store_stripe_cache_size); static ssize_t +raid5_show_preread_threshold(mddev_t *mddev, char *page) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + if (conf) + return sprintf(page, "%d\n", conf->bypass_threshold); + else + return 0; +} + +static ssize_t +raid5_store_preread_threshold(mddev_t *mddev, const char *page, size_t len) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + unsigned long new; + if (len >= PAGE_SIZE) + return -EINVAL; + if (!conf) + return -ENODEV; + + if (strict_strtoul(page, 10, &new)) + return -EINVAL; + if (new > conf->max_nr_stripes) + return -EINVAL; + conf->bypass_threshold = new; + return len; +} + +static struct md_sysfs_entry +raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold, + S_IRUGO | S_IWUSR, + raid5_show_preread_threshold, + raid5_store_preread_threshold); + +static ssize_t stripe_cache_active_show(mddev_t *mddev, char *page) { raid5_conf_t *conf = mddev_to_conf(mddev); @@ -4026,6 +4154,7 @@ raid5_stripecache_active = __ATTR_RO(stripe_cache_active); static struct attribute *raid5_attrs[] = { &raid5_stripecache_size.attr, &raid5_stripecache_active.attr, + &raid5_preread_bypass_threshold.attr, NULL, }; static struct attribute_group raid5_attrs_group = { @@ -4130,12 +4259,14 @@ static int run(mddev_t *mddev) init_waitqueue_head(&conf->wait_for_stripe); init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); + INIT_LIST_HEAD(&conf->hold_list); INIT_LIST_HEAD(&conf->delayed_list); INIT_LIST_HEAD(&conf->bitmap_list); INIT_LIST_HEAD(&conf->inactive_list); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); atomic_set(&conf->active_aligned_reads, 0); + conf->bypass_threshold = BYPASS_THRESHOLD; pr_debug("raid5: run(%s) called.\n", mdname(mddev)); diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c index 77a6e4bf503d..21987e3dbe6c 100644 --- a/drivers/md/raid6algos.c +++ b/drivers/md/raid6algos.c @@ -121,7 +121,8 @@ int __init raid6_select_algo(void) j0 = jiffies; while ( (j1 = jiffies) == j0 ) cpu_relax(); - while ( (jiffies-j1) < (1 << RAID6_TIME_JIFFIES_LG2) ) { + while (time_before(jiffies, + j1 + (1<<RAID6_TIME_JIFFIES_LG2))) { (*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs); perf++; } diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 128bb9cd5755..ddf57e135c6c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -5,16 +5,20 @@ menu "Multimedia devices" depends on HAS_IOMEM +comment "Multimedia core support" + +# +# V4L core and enabled API's +# + config VIDEO_DEV tristate "Video For Linux" ---help--- - Support for audio/video capture and overlay devices and FM radio - cards. The exact capabilities of each device vary. + V4L core support for video capture and overlay devices, webcams and + AM/FM radio cards. This kernel includes support for the new Video for Linux Two API, - (V4L2) as well as the original system. Drivers and applications - need to be rewritten to use V4L2, but drivers for popular cards - and applications for most video capture functions already exist. + (V4L2). Additional info and docs are available on the web at <http://linuxtv.org> @@ -36,8 +40,11 @@ config VIDEO_ALLOW_V4L1 default VIDEO_DEV && VIDEO_V4L2_COMMON select VIDEO_V4L1_COMPAT ---help--- - Enables a compatibility API used by most V4L2 devices to allow - its usage with legacy applications that supports only V4L1 api. + Enables drivers based on the legacy V4L1 API. + + This api were developed to be used at Kernel 2.2 and 2.4, but + lacks support for several video standards. There are several + drivers at kernel that still depends on it. If you are unsure as to whether this is required, answer Y. @@ -46,9 +53,8 @@ config VIDEO_V4L1_COMPAT depends on VIDEO_DEV default VIDEO_DEV ---help--- - This api were developed to be used at Kernel 2.2 and 2.4, but - lacks support for several video standards. There are several - drivers at kernel that still depends on it. + Enables a compatibility API used by most V4L2 devices to allow + its usage with legacy applications that supports only V4L1 api. Documentation for the original API is included in the file <Documentation/video4linux/API.html>. @@ -58,135 +64,57 @@ config VIDEO_V4L1_COMPAT If you are unsure as to whether this is required, answer Y. -config VIDEO_V4L2 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON - default VIDEO_DEV && VIDEO_V4L2_COMMON - -config VIDEO_V4L1 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 - default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 - -source "drivers/media/video/Kconfig" - -source "drivers/media/radio/Kconfig" - -source "drivers/media/dvb/Kconfig" - -source "drivers/media/common/Kconfig" +# +# DVB Core +# -config VIDEO_TUNER - tristate - depends on I2C - select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE - -menuconfig VIDEO_TUNER_CUSTOMIZE - bool "Customize analog tuner modules to build" - depends on VIDEO_TUNER +config DVB_CORE + tristate "DVB for Linux" + depends on NET && INET + select CRC32 help - This allows the user to deselect tuner drivers unnecessary - for their hardware from the build. Use this option with care - as deselecting tuner drivers which are in fact necessary will - result in V4L devices which cannot be tuned due to lack of - driver support + DVB core utility functions for device handling, software fallbacks etc. - If unsure say N. - -if VIDEO_TUNER_CUSTOMIZE - -config TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on I2C && FW_LOADER - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the xc2028/xc3028 tuners. + Enable this if you own a DVB/ATSC adapter and want to use it or if + you compile Linux for a digital SetTopBox. -config TUNER_MT20XX - tristate "Microtune 2032 / 2050 tuners" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the MT2032 / MT2050 tuner. - -config TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on I2C - select DVB_TDA827X - select DVB_TDA18271 - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA8290+8275(a) tuner. + Say Y when you have a DVB or an ATSC card and want to use it. -config TUNER_TEA5761 - tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on I2C && EXPERIMENTAL - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the Philips TEA5761 radio tuner. + API specs and user tools are available from <http://www.linuxtv.org/>. -config TUNER_TEA5767 - tristate "TEA 5767 radio tuner" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the Philips TEA5767 radio tuner. + Please report problems regarding this support to the LinuxDVB + mailing list. -config TUNER_SIMPLE - tristate "Simple tuner support" - depends on I2C - select TUNER_TDA9887 - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for various simple tuners. + If unsure say N. -config TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. +config VIDEO_MEDIA + tristate + default DVB_CORE || VIDEO_DEV + depends on DVB_CORE || VIDEO_DEV -endif # VIDEO_TUNER_CUSTOMIZE +comment "Multimedia drivers" -config VIDEOBUF_GEN - tristate +source "drivers/media/common/Kconfig" -config VIDEOBUF_DMA_SG - depends on HAS_DMA - select VIDEOBUF_GEN - tristate +# +# Tuner drivers for DVB and V4L +# -config VIDEOBUF_VMALLOC - select VIDEOBUF_GEN - tristate +source "drivers/media/common/tuners/Kconfig" -config VIDEOBUF_DVB - tristate - select VIDEOBUF_GEN - select VIDEOBUF_DMA_SG +# +# Video/Radio/Hybrid adapters +# -config VIDEO_BTCX - tristate +source "drivers/media/video/Kconfig" -config VIDEO_IR_I2C - tristate +source "drivers/media/radio/Kconfig" -config VIDEO_IR - tristate - depends on INPUT - select VIDEO_IR_I2C if I2C +# +# DVB adapters +# -config VIDEO_TVEEPROM - tristate - depends on I2C +source "drivers/media/dvb/Kconfig" config DAB boolean "DAB adapters" diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 7b8bb6949f5e..73f742c7e818 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,10 +2,10 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := common/ -obj-y += video/ +obj-$(CONFIG_VIDEO_MEDIA) += common/ + +# Since hybrid devices are here, should be compiled if DVB and/or V4L +obj-$(CONFIG_VIDEO_MEDIA) += video/ + obj-$(CONFIG_VIDEO_DEV) += radio/ obj-$(CONFIG_DVB_CORE) += dvb/ -ifeq ($(CONFIG_DVB_CORE),) - obj-$(CONFIG_VIDEO_TUNER) += dvb/frontends/ -endif diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 8e7448230643..351b98b9b302 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/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig new file mode 100644 index 000000000000..5be85ff53e12 --- /dev/null +++ b/drivers/media/common/tuners/Kconfig @@ -0,0 +1,151 @@ +config MEDIA_ATTACH + bool "Load and attach frontend and tuner driver modules as needed" + depends on DVB_CORE + depends on MODULES + help + Remove the static dependency of DVB card drivers on all + frontend modules for all possible card variants. Instead, + allow the card drivers to only load the frontend modules + they require. + + Also, tuner module will automatically load a tuner driver + when needed, for analog mode. + + This saves several KBytes of memory. + + Note: You will need module-init-tools v3.2 or later for this feature. + + If unsure say Y. + +config MEDIA_TUNER + tristate + default DVB_CORE || VIDEO_DEV + depends on DVB_CORE || VIDEO_DEV + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE + +menuconfig MEDIA_TUNER_CUSTOMIZE + bool "Customize analog and hybrid tuner modules to build" + depends on MEDIA_TUNER + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L/DVB devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +if MEDIA_TUNER_CUSTOMIZE + +config MEDIA_TUNER_SIMPLE + tristate "Simple tuner support" + depends on I2C + select MEDIA_TUNER_TDA9887 + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for various simple tuners. + +config MEDIA_TUNER_TDA8290 + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + depends on I2C + select MEDIA_TUNER_TDA827X + select MEDIA_TUNER_TDA18271 + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config MEDIA_TUNER_TDA827X + tristate "Philips TDA827X silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + +config MEDIA_TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config MEDIA_TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config MEDIA_TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config MEDIA_TUNER_MT2060 + tristate "Microtune MT2060 silicon IF tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon IF tuner MT2060 from Microtune. + +config MEDIA_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + +config MEDIA_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + +config MEDIA_TUNER_QT1010 + tristate "Quantek QT1010 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner QT1010 from Quantek. + +config MEDIA_TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on I2C && FW_LOADER + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the xc2028/xc3028 tuners. + +config MEDIA_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called togther with a + demodulator for now. + +endif # MEDIA_TUNER_CUSTOMIZE diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile new file mode 100644 index 000000000000..236d9932fd92 --- /dev/null +++ b/drivers/media/common/tuners/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for common V4L/DVB tuners +# + +tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o + +obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o +# tuner-types will be merged into tuner-simple, in the future +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o +obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o +obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o +obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o +obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o +obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/common/tuners/mt2060.c index 1305b0e63ce5..1305b0e63ce5 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/common/tuners/mt2060.c diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/common/tuners/mt2060.h index acba0058f519..cb60caffb6b6 100644 --- a/drivers/media/dvb/frontends/mt2060.h +++ b/drivers/media/common/tuners/mt2060.h @@ -30,7 +30,7 @@ struct mt2060_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); #else static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) @@ -38,6 +38,6 @@ static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struc printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2060 +#endif // CONFIG_MEDIA_TUNER_MT2060 #endif diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h index 5eaccdefd0b0..5eaccdefd0b0 100644 --- a/drivers/media/dvb/frontends/mt2060_priv.h +++ b/drivers/media/common/tuners/mt2060_priv.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/common/tuners/mt20xx.c index fbcb28233737..fbcb28233737 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/common/tuners/mt20xx.c diff --git a/drivers/media/video/mt20xx.h b/drivers/media/common/tuners/mt20xx.h index aa848e14ce5e..259553a24903 100644 --- a/drivers/media/video/mt20xx.h +++ b/drivers/media/common/tuners/mt20xx.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/common/tuners/mt2131.c index e254bcfc2efb..e254bcfc2efb 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/common/tuners/mt2131.c diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/common/tuners/mt2131.h index 606d8576bc98..cd8376f6f7b4 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/common/tuners/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, @@ -44,7 +44,7 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif /* CONFIG_DVB_TUNER_MT2131 */ +#endif /* CONFIG_MEDIA_TUNER_MT2131 */ #endif /* __MT2131_H__ */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h index e930759c2c00..e930759c2c00 100644 --- a/drivers/media/dvb/frontends/mt2131_priv.h +++ b/drivers/media/common/tuners/mt2131_priv.h diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/common/tuners/mt2266.c index 54b18f94b14b..54b18f94b14b 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/common/tuners/mt2266.c diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/common/tuners/mt2266.h index c5113efe333c..4d083882d044 100644 --- a/drivers/media/dvb/frontends/mt2266.h +++ b/drivers/media/common/tuners/mt2266.h @@ -24,7 +24,7 @@ struct mt2266_config { u8 i2c_address; }; -#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); #else static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) @@ -32,6 +32,6 @@ static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struc printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2266 +#endif // CONFIG_MEDIA_TUNER_MT2266 #endif diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/common/tuners/qt1010.c index 825aa1412e6f..825aa1412e6f 100644 --- a/drivers/media/dvb/frontends/qt1010.c +++ b/drivers/media/common/tuners/qt1010.c diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/common/tuners/qt1010.h index cff6a7ca5380..807fb7b6146b 100644 --- a/drivers/media/dvb/frontends/qt1010.h +++ b/drivers/media/common/tuners/qt1010.h @@ -36,7 +36,7 @@ struct qt1010_config { * @param cfg tuner hw based configuration * @return fe pointer on success, NULL on failure */ -#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct qt1010_config *cfg); @@ -48,6 +48,6 @@ static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_QT1010 +#endif // CONFIG_MEDIA_TUNER_QT1010 #endif diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h index 090cf475f099..090cf475f099 100644 --- a/drivers/media/dvb/frontends/qt1010_priv.h +++ b/drivers/media/common/tuners/qt1010_priv.h diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index e27a7620a32f..e27a7620a32f 100644 --- a/drivers/media/dvb/frontends/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index b262100ae897..b262100ae897 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/common/tuners/tda18271-maps.c index 83e7561960c1..83e7561960c1 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/common/tuners/tda18271-maps.c diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 2bc5eb368ea2..2bc5eb368ea2 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/common/tuners/tda18271.h index 0e7af8d05a38..7db9831c0cb0 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h @@ -81,7 +81,7 @@ struct tda18271_config { unsigned int small_i2c:1; }; -#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, struct tda18271_config *cfg); diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/common/tuners/tda827x.c index d30d2c9094d9..d30d2c9094d9 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/common/tuners/tda827x.h index b73c23570dab..7850a9a1dc8f 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/common/tuners/tda827x.h @@ -51,7 +51,7 @@ struct tda827x_config * @param cfg optional callback function pointers. * @return FE pointer on success, NULL on failure. */ -#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, struct tda827x_config *cfg); @@ -64,6 +64,6 @@ static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TDA827X +#endif // CONFIG_MEDIA_TUNER_TDA827X #endif // __DVB_TDA827X_H__ diff --git a/drivers/media/video/tda8290.c b/drivers/media/common/tuners/tda8290.c index 0ebb5b525e57..91204d3f282d 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -578,16 +578,16 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if ((data == 0x83) || (data == 0x84)) { priv->ver |= TDA18271; - tda18271_attach(fe, priv->tda827x_addr, - priv->i2c_props.adap, - &tda829x_tda18271_config); + dvb_attach(tda18271_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &tda829x_tda18271_config); } else { if ((data & 0x3c) == 0) priv->ver |= TDA8275; else priv->ver |= TDA8275A; - tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); + dvb_attach(tda827x_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); priv->cfg.switch_addr = priv->i2c_props.addr; } if (fe->ops.tuner_ops.init) diff --git a/drivers/media/video/tda8290.h b/drivers/media/common/tuners/tda8290.h index d3bbf276a469..aa074f3f0c07 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/common/tuners/tda8290.h @@ -29,7 +29,7 @@ struct tda829x_config { #define TDA829X_DONT_PROBE 1 }; -#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tda9887.c b/drivers/media/common/tuners/tda9887.c index a0545ba957b0..a0545ba957b0 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/common/tuners/tda9887.c diff --git a/drivers/media/video/tda9887.h b/drivers/media/common/tuners/tda9887.h index be49dcbfc70e..acc419e8c4fc 100644 --- a/drivers/media/video/tda9887.h +++ b/drivers/media/common/tuners/tda9887.h @@ -21,7 +21,7 @@ #include "dvb_frontend.h" /* ------------------------------------------------------------------------ */ -#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr); diff --git a/drivers/media/video/tea5761.c b/drivers/media/common/tuners/tea5761.c index b93cdef9ac73..b93cdef9ac73 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/common/tuners/tea5761.c diff --git a/drivers/media/video/tea5761.h b/drivers/media/common/tuners/tea5761.h index 8eb62722b988..2e2ff82c95a4 100644 --- a/drivers/media/video/tea5761.h +++ b/drivers/media/common/tuners/tea5761.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tea5767.c b/drivers/media/common/tuners/tea5767.c index f6e7d7ad8424..f6e7d7ad8424 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/common/tuners/tea5767.c diff --git a/drivers/media/video/tea5767.h b/drivers/media/common/tuners/tea5767.h index 7b547c092e25..d30ab1b483de 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/common/tuners/tea5767.h @@ -39,7 +39,7 @@ struct tea5767_ctrl { enum tea5767_xtal xtal_freq; }; -#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h index 3ad6c8e0b04c..3ad6c8e0b04c 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/common/tuners/tuner-i2c.h diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index be8d903171b7..be8d903171b7 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h index e46cf0121e03..381fa5d35a9b 100644 --- a/drivers/media/video/tuner-simple.h +++ b/drivers/media/common/tuners/tuner-simple.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, diff --git a/drivers/media/video/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 10dddca8b5d1..10dddca8b5d1 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h index 74dc46a71f64..74dc46a71f64 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/common/tuners/tuner-xc2028-types.h diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 9e9003cffc7f..9e9003cffc7f 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h index fc2f132a5541..216025cf5d4b 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/common/tuners/tuner-xc2028.h @@ -47,7 +47,7 @@ struct xc2028_config { #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 -#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); #else diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/common/tuners/xc5000.c index 43d35bdb221f..43d35bdb221f 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/common/tuners/xc5000.h index b890883a0cdc..0ee80f9d19b8 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/common/tuners/xc5000.h @@ -45,8 +45,8 @@ struct xc5000_config { /* xc5000 callback command */ #define XC5000_TUNER_RESET 0 -#if defined(CONFIG_DVB_TUNER_XC5000) || \ - (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ + (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct xc5000_config *cfg); @@ -58,6 +58,6 @@ static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_XC5000 +#endif // CONFIG_MEDIA_TUNER_XC5000 #endif // __XC5000_H__ diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h index 13b2d19341da..13b2d19341da 100644 --- a/drivers/media/dvb/frontends/xc5000_priv.h +++ b/drivers/media/common/tuners/xc5000_priv.h diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 03ef88acd9b8..7b21b49f1945 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -1,9 +1,7 @@ # -# Multimedia device configuration +# DVB device configuration # -source "drivers/media/dvb/dvb-core/Kconfig" - menuconfig DVB_CAPTURE_DRIVERS bool "DVB/ATSC adapters" depends on DVB_CORE diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 6ec5afba1ca7..73dc2ee9b014 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -9,7 +9,7 @@ config DVB_B2C2_FLEXCOP select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_BCM3510 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 870e2848c296..d9db066f9854 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -14,4 +14,4 @@ b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/video/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 902c762e0b7f..d1239b8342f8 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -8,7 +8,7 @@ config DVB_BT8XX select DVB_OR51211 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index 9d3e68b5d6eb..d98f1d49ffa8 100644 --- a/drivers/media/dvb/bt8xx/Makefile +++ b/drivers/media/dvb/bt8xx/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends EXTRA_CFLAGS += -Idrivers/media/video/bt8xx -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 75711bde23ad..a7637562e742 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1714,7 +1714,7 @@ static void dst_release(struct dvb_frontend *fe) struct dst_state *state = fe->demodulator_priv; if (state->dst_ca) { dvb_unregister_device(state->dst_ca); -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH symbol_put(dst_ca_attach); #endif } diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig deleted file mode 100644 index e3e6839f8073..000000000000 --- a/drivers/media/dvb/dvb-core/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config DVB_CORE - tristate "DVB for Linux" - depends on NET && INET - select CRC32 - help - Support Digital Video Broadcasting hardware. Enable this if you - own a DVB adapter and want to use it or if you compile Linux for - a digital SetTopBox. - - DVB core utility functions for device handling, software fallbacks etc. - Say Y when you have a DVB card and want to use it. Say Y if your want - to build your drivers outside the kernel, but need the DVB core. All - in-kernel drivers will select this automatically if needed. - - API specs and user tools are available from <http://www.linuxtv.org/>. - - Please report problems regarding this driver to the LinuxDVB - mailing list. - - If unsure say N. - -config DVB_CORE_ATTACH - bool "Load and attach frontend modules as needed" - depends on DVB_CORE - depends on MODULES - help - Remove the static dependency of DVB card drivers on all - frontend modules for all possible card variants. Instead, - allow the card drivers to only load the frontend modules - they require. This saves several KBytes of memory. - - Note: You will need module-init-tools v3.2 or later for this feature. - - If unsure say Y. diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2dddd08c5445..8cbdb218952f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1189,7 +1189,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) } EXPORT_SYMBOL(dvb_unregister_frontend); -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH void dvb_frontend_detach(struct dvb_frontend* fe) { void *ptr; diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 5f9a737c6de1..89d12dc477a7 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -115,7 +115,7 @@ extern int dvb_usercopy(struct inode *inode, struct file *file, unsigned int cmd, void *arg)); /** generic DVB attach function. */ -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 3c8493d2026d..4c1cff9feb2e 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -25,7 +25,7 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. @@ -35,7 +35,7 @@ config DVB_USB_DIBUSB_MB depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MB - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. @@ -56,7 +56,7 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. @@ -73,8 +73,8 @@ config DVB_USB_DIB0700 select DVB_DIB7000P select DVB_DIB7000M select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The @@ -93,7 +93,7 @@ config DVB_USB_UMT_010 depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. @@ -105,7 +105,7 @@ config DVB_USB_CXUSB select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -118,7 +118,7 @@ config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of @@ -129,7 +129,7 @@ config DVB_USB_GL861 tristate "Genesys Logic GL861 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 receiver with USB ID 0db0:5581. @@ -138,7 +138,7 @@ config DVB_USB_AU6610 tristate "Alcor Micro AU6610 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. @@ -190,7 +190,7 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. @@ -227,8 +227,8 @@ config DVB_USB_OPERA1 config DVB_USB_AF9005 tristate "Afatech AF9005 DVB-T USB1.1 support" depends on DVB_USB && EXPERIMENTAL - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver and the TerraTec Cinergy T USB XE (Rev.1) diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 60a910052c16..c6511a6c0ab8 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -63,5 +63,5 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index f5fceb3cdb3c..6d2384605927 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -15,22 +15,36 @@ config DVB_FE_CUSTOMISE comment "DVB-S (satellite) frontends" depends on DVB_CORE -config DVB_STV0299 - tristate "ST STV0299 based" +config DVB_CX24110 + tristate "Conexant CX24110 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_CX24110 - tristate "Conexant CX24110 based" +config DVB_CX24123 + tristate "Conexant CX24123 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_CX24123 - tristate "Conexant CX24123 based" +config DVB_MT312 + tristate "Zarlink VP310/MT312 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_S5H1420 + tristate "Samsung S5H1420 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STV0299 + tristate "ST STV0299 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -43,8 +57,8 @@ config DVB_TDA8083 help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_MT312 - tristate "Zarlink VP310/MT312 based" +config DVB_TDA10086 + tristate "Philips TDA10086 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -57,19 +71,26 @@ config DVB_VES1X93 help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_S5H1420 - tristate "Samsung S5H1420 based" +config DVB_TUNER_ITD1000 + tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_TDA10086 - tristate "Philips TDA10086 based" +config DVB_TDA826X + tristate "Philips TDA826X silicon tuner" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - A DVB-S tuner module. Say Y when you want to support this frontend. + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + +config DVB_TUA6100 + tristate "Infineon TUA6100 PLL" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S PLL chip. comment "DVB-T (terrestrial) frontends" depends on DVB_CORE @@ -315,7 +336,7 @@ config DVB_S5H1411 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. -comment "Tuners/PLL support" +comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE config DVB_PLL @@ -326,55 +347,6 @@ config DVB_PLL This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. -config DVB_TDA826X - tristate "Philips TDA826X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TUNER_QT1010 - tristate "Quantek QT1010 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner QT1010 from Quantek. - -config DVB_TUNER_MT2060 - tristate "Microtune MT2060 silicon IF tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon IF tuner MT2060 from Microtune. - -config DVB_TUNER_MT2266 - tristate "Microtune MT2266 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner MT2266 from Microtune. - -config DVB_TUNER_MT2131 - tristate "Microtune MT2131 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner MT2131 from Microtune. - config DVB_TUNER_DIB0070 tristate "DiBcom DiB0070 silicon base-band tuner" depends on I2C @@ -384,21 +356,7 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called togther with a demodulator for now. -config DVB_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called togther with a - demodulator for now. - -config DVB_TUNER_ITD1000 - tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - -comment "Miscellaneous devices" +comment "SEC control devices for DVB-S" depends on DVB_CORE config DVB_LNBP21 @@ -422,11 +380,4 @@ config DVB_ISL6421 help An SEC control chip. -config DVB_TUA6100 - tristate "TUA6100 PLL" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVBS PLL chip. - endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 9747c73dc826..a89dc0fc4c6f 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -3,9 +3,7 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/video/ - -tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -42,16 +40,9 @@ obj-$(CONFIG_DVB_ISL6405) += isl6405.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o -obj-$(CONFIG_DVB_TDA827X) += tda827x.o -obj-$(CONFIG_DVB_TDA18271) += tda18271.o -obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o -obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o -obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o -obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o -obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 281e1cb2edc6..720ed9ff7c5f 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -481,7 +481,7 @@ static void s5h1420_setsymbolrate(struct s5h1420_state* state, val *= 2; do_div(val, (state->fclk / 1000)); - dprintk("symbol rate register: %06llx\n", val); + dprintk("symbol rate register: %06llx\n", (unsigned long long)val); v = s5h1420_readreg(state, Loop01); s5h1420_writereg(state, Loop01, v & 0x7f); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fe9a4cc14141..fe743aa7f645 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1,4 +1,50 @@ # +# Generic video config states +# + +config VIDEO_V4L2 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON + default VIDEO_DEV && VIDEO_V4L2_COMMON + +config VIDEO_V4L1 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 + default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 + +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG + depends on HAS_DMA + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_DVB + tristate + select VIDEOBUF_GEN + select VIDEOBUF_DMA_SG + +config VIDEO_BTCX + tristate + +config VIDEO_IR_I2C + tristate + +config VIDEO_IR + tristate + depends on INPUT + select VIDEO_IR_I2C if I2C + +config VIDEO_TVEEPROM + tristate + depends on I2C + +# # Multimedia Video device configuration # @@ -644,7 +690,7 @@ config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_V4L1 && I2C select VIDEO_SAA7146_VV - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO @@ -702,6 +748,8 @@ source "drivers/media/video/au0828/Kconfig" source "drivers/media/video/ivtv/Kconfig" +source "drivers/media/video/cx18/Kconfig" + config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index be14227f3726..a352c6e31f0c 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -84,17 +84,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o -obj-$(CONFIG_VIDEO_TUNER) += tuner.o - -obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o -obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o -# tuner-types will be merged into tuner-simple, in the future -obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o -obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o -obj-$(CONFIG_TUNER_TDA8290) += tda8290.o -obj-$(CONFIG_TUNER_TEA5767) += tea5767.o -obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER) += tuner.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o @@ -134,6 +124,7 @@ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ @@ -147,3 +138,4 @@ obj-$(CONFIG_VIDEO_AU0828) += au0828/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index 41708267e7a4..cab277fafa63 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -4,7 +4,7 @@ config VIDEO_AU0828 depends on VIDEO_DEV && I2C && INPUT && DVB_CORE select I2C_ALGOBIT select DVB_AU8522 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile index 9f4f572c89c5..cd2c58281b4e 100644 --- a/drivers/media/video/au0828/Makefile +++ b/drivers/media/video/au0828/Makefile @@ -2,7 +2,7 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o obj-$(CONFIG_VIDEO_AU0828) += au0828.o -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c index 5040d7fc4af5..1371b4e4b5f1 100644 --- a/drivers/media/video/au0828/au0828-dvb.c +++ b/drivers/media/video/au0828/au0828-dvb.c @@ -119,7 +119,7 @@ static int start_urb_transfer(struct au0828_dev *dev) purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); if (!purb->transfer_buffer) { usb_free_urb(purb); - dev->urbs[i] = 0; + dev->urbs[i] = NULL; goto err; } diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index cfc822bb502a..7431ef6de9f1 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -6,7 +6,7 @@ config VIDEO_BT848 select VIDEO_BTCX select VIDEOBUF_DMA_SG select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index 924d216d9570..e415f6fc447c 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -9,4 +9,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 03816b73f847..27da7b423275 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/cs5345.c b/drivers/media/video/cs5345.c index fae469ce16f5..2a429f9e32cd 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -142,7 +142,8 @@ static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) /* ----------------------------------------------------------------------- */ -static int cs5345_probe(struct i2c_client *client) +static int cs5345_probe(struct i2c_client *client, + const struct i2c_device_id *id) { /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index f41bfde045fe..2dfd0afc62db 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -135,7 +135,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int cs53l32a_probe(struct i2c_client *client) +static int cs53l32a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int i; diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig new file mode 100644 index 000000000000..acc4b47f1d1d --- /dev/null +++ b/drivers/media/video/cx18/Kconfig @@ -0,0 +1,20 @@ +config VIDEO_CX18 + tristate "Conexant cx23418 MPEG encoder support" + depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_IR + select MEDIA_TUNER + select VIDEO_TVEEPROM + select VIDEO_CX2341X + select VIDEO_CS5345 + select DVB_S5H1409 + ---help--- + This is a video4linux driver for Conexant cx23418 based + PCI combo video recorder devices. + + This is used in devices such as the Hauppauge HVR-1600 + cards. + + To compile this driver as a module, choose M here: the + module will be called cx18. diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile new file mode 100644 index 000000000000..b23d2e26120f --- /dev/null +++ b/drivers/media/video/cx18/Makefile @@ -0,0 +1,11 @@ +cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ + cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ + cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ + cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ + cx18-dvb.o + +obj-$(CONFIG_VIDEO_CX18) += cx18.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c new file mode 100644 index 000000000000..1adc404d955e --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.c @@ -0,0 +1,73 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-i2c.h" +#include "cx18-cards.h" +#include "cx18-audio.h" + +/* Selects the audio input and output according to the current + settings. */ +int cx18_audio_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + u32 audio_input; + int mux_input; + + /* Determine which input to use */ + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + audio_input = cx->card->radio_input.audio_input; + mux_input = cx->card->radio_input.muxer_input; + } else { + audio_input = + cx->card->audio_inputs[cx->audio_input].audio_input; + mux_input = + cx->card->audio_inputs[cx->audio_input].muxer_input; + } + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, &route); +} + +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route) +{ + cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, route); +} + +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq) +{ + static u32 freqs[3] = { 44100, 48000, 32000 }; + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (freq > 2) + return; + cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); +} diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h new file mode 100644 index 000000000000..cb569a69379c --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.h @@ -0,0 +1,26 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +int cx18_audio_set_io(struct cx18 *cx); +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route); +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq); diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c new file mode 100644 index 000000000000..2dc3a5dd170e --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -0,0 +1,361 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +static int set_audclk_freq(struct cx18 *cx, u32 freq) +{ + struct cx18_av_state *state = &cx->av_state; + + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + + /* common for all inputs and rates */ + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ + cx18_av_write(cx, 0x127, 0x50); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1006040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x01bb39ee); + + /* src3/4/6_ctl = 0x0801f77f */ + cx18_av_write4(cx, 0x900, 0x0801f77f); + cx18_av_write4(cx, 0x904, 0x0801f77f); + cx18_av_write4(cx, 0x90c, 0x0801f77f); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1009040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src3/4/6_ctl = 0x08016d59 */ + cx18_av_write4(cx, 0x900, 0x08016d59); + cx18_av_write4(cx, 0x904, 0x08016d59); + cx18_av_write4(cx, 0x90c, 0x08016d59); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x100a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src3/4/6_ctl = 0x08014faa */ + cx18_av_write4(cx, 0x900, 0x08014faa); + cx18_av_write4(cx, 0x904, 0x08014faa); + cx18_av_write4(cx, 0x90c, 0x08014faa); + break; + } + } else { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1e08040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x012a0869); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08010000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08020000); + cx18_av_write4(cx, 0x904, 0x08020000); + cx18_av_write4(cx, 0x90c, 0x08020000); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ + cx18_av_write(cx, 0x127, 0x54); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1809040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08017385); + cx18_av_write4(cx, 0x904, 0x08017385); + cx18_av_write4(cx, 0x90c, 0x08017385); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x180a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08018000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08015555); + cx18_av_write4(cx, 0x904, 0x08015555); + cx18_av_write4(cx, 0x90c, 0x08015555); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +void cx18_av_audio_set_path(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + + /* stop microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0); + + /* assert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x01); + + /* Mute everything to prevent the PFFT! */ + cx18_av_write(cx, 0x8d3, 0x1f); + + if (state->aud_input == CX18_AV_AUDIO_SERIAL) { + /* Set Path1 to Serial Audio Input */ + cx18_av_write4(cx, 0x8d0, 0x01011012); + + /* The microcontroller should not be started for the + * non-tuner inputs: autodetection is specific for + * TV audio. */ + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx18_av_write4(cx, 0x8d0, 0x1f063870); + } + + set_audclk_freq(cx, state->audclk_freq); + + /* deassert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x00); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int get_volume(struct cx18 *cx) +{ + /* Volume runs +18dB to -96dB in 1/2dB steps + * change to fit the msp3400 -114dB to +12dB range */ + + /* check PATH1_VOLUME */ + int vol = 228 - cx18_av_read(cx, 0x8d4); + vol = (vol / 2) + 23; + return vol << 9; +} + +static void set_volume(struct cx18 *cx, int volume) +{ + /* First convert the volume to msp3400 values (0-127) */ + int vol = volume >> 9; + /* now scale it up to cx18_av values + * -114dB to -96dB maps to 0 + * this should be 19, but in my testing that was 4dB too loud */ + if (vol <= 23) + vol = 0; + else + vol -= 23; + + /* PATH1_VOLUME */ + cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); +} + +static int get_bass(struct cx18 *cx) +{ + /* bass is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_BASS_VOL */ + int bass = cx18_av_read(cx, 0x8d9) & 0x3f; + bass = (((48 - bass) * 0xffff) + 47) / 48; + return bass; +} + +static void set_bass(struct cx18 *cx, int bass) +{ + /* PATH1_EQ_BASS_VOL */ + cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); +} + +static int get_treble(struct cx18 *cx) +{ + /* treble is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_TREBLE_VOL */ + int treble = cx18_av_read(cx, 0x8db) & 0x3f; + treble = (((48 - treble) * 0xffff) + 47) / 48; + return treble; +} + +static void set_treble(struct cx18 *cx, int treble) +{ + /* PATH1_EQ_TREBLE_VOL */ + cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); +} + +static int get_balance(struct cx18 *cx) +{ + /* balance is 7 bit, 0 to -96dB */ + + /* check PATH1_BAL_LEVEL */ + int balance = cx18_av_read(cx, 0x8d5) & 0x7f; + /* check PATH1_BAL_LEFT */ + if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) + balance = 0x80 - balance; + else + balance = 0x80 + balance; + return balance << 8; +} + +static void set_balance(struct cx18 *cx, int balance) +{ + int bal = balance >> 8; + if (bal > 0x80) { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); + } else { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); + } +} + +static int get_mute(struct cx18 *cx) +{ + /* check SRC1_MUTE_EN */ + return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; +} + +static void set_mute(struct cx18 *cx, int mute) +{ + struct cx18_av_state *state = &cx->av_state; + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* Must turn off microcontroller in order to mute sound. + * Not sure if this is the best method, but it does work. + * If the microcontroller is running, then it will undo any + * changes to the mute register. */ + if (mute) { + /* disable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_write(cx, 0x8d3, 0x1f); + } else { + /* enable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } + } else { + /* SRC1_MUTE_EN */ + cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + } +} + +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_control *ctrl = arg; + int retval; + + switch (cmd) { + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + cx18_av_and_or(cx, 0x803, ~0x10, 0); + cx18_av_write(cx, 0x8d3, 0x1f); + } + cx18_av_and_or(cx, 0x810, ~0x1, 1); + retval = set_audclk_freq(cx, *(u32 *)arg); + cx18_av_and_or(cx, 0x810, ~0x1, 0); + if (state->aud_input != CX18_AV_AUDIO_SERIAL) + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + return retval; + + case VIDIOC_G_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = get_volume(cx); + break; + case V4L2_CID_AUDIO_BASS: + ctrl->value = get_bass(cx); + break; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = get_treble(cx); + break; + case V4L2_CID_AUDIO_BALANCE: + ctrl->value = get_balance(cx); + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = get_mute(cx); + break; + default: + return -EINVAL; + } + break; + + case VIDIOC_S_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + set_volume(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BASS: + set_bass(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_TREBLE: + set_treble(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BALANCE: + set_balance(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_MUTE: + set_mute(cx, ctrl->value); + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c new file mode 100644 index 000000000000..66864904c99b --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -0,0 +1,879 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-core.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + u32 mask = 0xff; + int shift = (addr & 3) * 8; + + x = (x & ~(mask << shift)) | ((u32)value << shift); + writel(x, cx->reg_mem + 0xc40000 + (addr & ~3)); + return 0; +} + +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) +{ + writel(value, cx->reg_mem + 0xc40000 + addr); + return 0; +} + +u8 cx18_av_read(struct cx18 *cx, u16 addr) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + int shift = (addr & 3) * 8; + + return (x >> shift) & 0xff; +} + +u32 cx18_av_read4(struct cx18 *cx, u16 addr) +{ + return readl(cx->reg_mem + 0xc40000 + addr); +} + +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, + u8 or_value) +{ + return cx18_av_write(cx, addr, + (cx18_av_read(cx, addr) & and_mask) | + or_value); +} + +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, + u32 or_value) +{ + return cx18_av_write4(cx, addr, + (cx18_av_read4(cx, addr) & and_mask) | + or_value); +} + +/* ----------------------------------------------------------------------- */ + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input); +static void log_audio_status(struct cx18 *cx); +static void log_video_status(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ + +static void cx18_av_initialize(struct cx18 *cx) +{ + u32 v; + + cx18_av_loadfw(cx); + /* Stop 8051 code execution */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000); + + /* initallize the PLL by toggling sleep bit */ + v = cx18_av_read4(cx, CXADEC_HOST_REG1); + /* enable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1); + /* disable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe); + + /* initialize DLLs */ + v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); + + v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); + + /* set analog bias currents. Set Vreg to 1.20V. */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); + + v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; + /* enable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v); + /* disable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE); + + /* enable 656 output */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); + + /* video output drive strength */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); + + /* reset video */ + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); + + /* set video to auto-detect */ + /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ + /* set the comb notch = 1 */ + cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); + + /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ + /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ + cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); + + /* Set VGA_TRACK_RANGE to 0x20 */ + cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); + + /* Enable VBI capture */ + cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F); + /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */ + + /* Set the video input. + The setting in MODE_CTRL gets lost when we do the above setup */ + /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ + /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ + + v = cx18_av_read4(cx, CXADEC_AFE_CTRL); + v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */ + v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */ + v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */ + /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */ + cx18_av_write4(cx, CXADEC_AFE_CTRL, v); + +/* if(dwEnable && dw3DCombAvailable) { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ +/* } else { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ +/* } */ + cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); +} + +/* ----------------------------------------------------------------------- */ + +static void input_change(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + + /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ + if (std & V4L2_STD_SECAM) + cx18_av_write(cx, 0x402, 0); + else { + cx18_av_write(cx, 0x402, 0x04); + cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + } + cx18_av_and_or(cx, 0x401, ~0x60, 0); + cx18_av_and_or(cx, 0x401, ~0x60, 0x60); + + if (std & V4L2_STD_525_60) { + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx18_av_write(cx, 0x808, 0xf7); + } else if (std == V4L2_STD_NTSC_M_KR) { + /* South Korea uses A2 audio standard */ + cx18_av_write(cx, 0x808, 0xf8); + } else { + /* Others use the BTSC audio standard */ + cx18_av_write(cx, 0x808, 0xf6); + } + cx18_av_write(cx, 0x80b, 0x00); + } else if (std & V4L2_STD_PAL) { + /* Follow tuner change procedure for PAL */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } else if (std & V4L2_STD_SECAM) { + /* Select autodetect for SECAM */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } + + if (cx18_av_read(cx, 0x803) & 0x10) { + /* restart audio decoder microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input) +{ + struct cx18_av_state *state = &cx->av_state; + u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8); + u8 reg; + + CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n", + vid_input, aud_input); + + if (is_composite) { + reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); + } else { + int luma = vid_input & 0xf0; + int chroma = vid_input & 0xf00; + + if ((vid_input & ~0xff0) || + luma < CX18_AV_SVIDEO_LUMA1 || + luma > CX18_AV_SVIDEO_LUMA4 || + chroma < CX18_AV_SVIDEO_CHROMA4 || + chroma > CX18_AV_SVIDEO_CHROMA8) { + CX18_ERR("0x%04x is not a valid video input!\n", + vid_input); + return -EINVAL; + } + reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); + if (chroma >= CX18_AV_SVIDEO_CHROMA7) { + reg &= 0x3f; + reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; + } else { + reg &= 0xcf; + reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; + } + } + + switch (aud_input) { + case CX18_AV_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX18_AV_AUDIO4: reg &= ~0x30; break; + case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX18_AV_AUDIO7: reg &= ~0xc0; break; + case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + + default: + CX18_ERR("0x%04x is not a valid audio input!\n", aud_input); + return -EINVAL; + } + + cx18_av_write(cx, 0x103, reg); + /* Set INPUT_MODE to Composite (0) or S-Video (1) */ + cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx18_av_and_or(cx, 0x102, ~0x4, 4); + else + cx18_av_and_or(cx, 0x102, ~0x4, 0); + /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/ + + state->vid_input = vid_input; + state->aud_input = aud_input; + cx18_av_audio_set_path(cx); + input_change(cx); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lstd(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { + pal_m = 1; + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { + fmt = 0x8; + } else { + /* Then, test against generic ones */ + if (state->std & V4L2_STD_NTSC) + fmt = 0x1; + else if (state->std & V4L2_STD_PAL) + fmt = 0x4; + else if (state->std & V4L2_STD_SECAM) + fmt = 0xc; + } + + CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt); + + /* Follow step 9 of section 3.16 in the cx18_av datasheet. + Without this PAL may display a vertical ghosting effect. + This happens for example with the Yuan MPC622. */ + if (fmt >= 4 && fmt < 8) { + /* Set format to NTSC-M */ + cx18_av_and_or(cx, 0x400, ~0xf, 1); + /* Turn off LCOMB */ + cx18_av_and_or(cx, 0x47b, ~6, 0); + } + cx18_av_and_or(cx, 0x400, ~0xf, fmt); + cx18_av_and_or(cx, 0x403, ~0x3, pal_m); + cx18_av_vbi_setup(cx); + input_change(cx); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (ctrl->value < 0 || ctrl->value > 255) { + CX18_ERR("invalid brightness setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x414, ctrl->value - 128); + break; + + case V4L2_CID_CONTRAST: + if (ctrl->value < 0 || ctrl->value > 127) { + CX18_ERR("invalid contrast setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x415, ctrl->value << 1); + break; + + case V4L2_CID_SATURATION: + if (ctrl->value < 0 || ctrl->value > 127) { + CX18_ERR("invalid saturation setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x420, ctrl->value << 1); + cx18_av_write(cx, 0x421, ctrl->value << 1); + break; + + case V4L2_CID_HUE: + if (ctrl->value < -127 || ctrl->value > 127) { + CX18_ERR("invalid hue setting %d\n", ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x422, ctrl->value); + break; + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl); + + default: + return -EINVAL; + } + + return 0; +} + +static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; + break; + case V4L2_CID_CONTRAST: + ctrl->value = cx18_av_read(cx, 0x415) >> 1; + break; + case V4L2_CID_SATURATION: + ctrl->value = cx18_av_read(cx, 0x420) >> 1; + break; + case V4L2_CID_HUE: + ctrl->value = (s8)cx18_av_read(cx, 0x422); + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl); + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) +{ + switch (fmt->type) { + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt); + default: + return -EINVAL; + } + + return 0; +} + +static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_pix_format *pix; + int HSC, VSC, Vsrc, Hsrc, filter, Vlines; + int is_50Hz = !(state->std & V4L2_STD_525_60); + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pix = &(fmt->fmt.pix); + + Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; + Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; + + Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; + Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; + + Vlines = pix->height + (is_50Hz ? 4 : 7); + + if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + CX18_ERR("%dx%d is not a valid size!\n", + pix->width, pix->height); + return -ERANGE; + } + + HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (pix->width >= 385) + filter = 0; + else if (pix->width > 192) + filter = 1; + else if (pix->width > 96) + filter = 2; + else + filter = 3; + + CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n", + pix->width, pix->height, HSC, VSC); + + /* HSCALE=HSC */ + cx18_av_write(cx, 0x418, HSC & 0xff); + cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); + cx18_av_write(cx, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx18_av_write(cx, 0x41c, VSC & 0xff); + cx18_av_write(cx, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx18_av_write(cx, 0x41e, 0x8 | filter); + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt); + + case V4L2_BUF_TYPE_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt); + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_tuner *vt = arg; + struct v4l2_routing *route = arg; + + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + cx18_av_initialize(cx); + } + + switch (cmd) { + case VIDIOC_INT_DECODE_VBI_LINE: + return cx18_av_vbi(cx, cmd, arg); + + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + return cx18_av_audio(cx, cmd, arg); + + case VIDIOC_STREAMON: + CX18_DEBUG_INFO("enable output\n"); + cx18_av_write(cx, 0x115, 0x8c); + cx18_av_write(cx, 0x116, 0x07); + break; + + case VIDIOC_STREAMOFF: + CX18_DEBUG_INFO("disable output\n"); + cx18_av_write(cx, 0x115, 0x00); + cx18_av_write(cx, 0x116, 0x00); + break; + + case VIDIOC_LOG_STATUS: + log_video_status(cx); + log_audio_status(cx); + break; + + case VIDIOC_G_CTRL: + return get_v4lctrl(cx, (struct v4l2_control *)arg); + + case VIDIOC_S_CTRL: + return set_v4lctrl(cx, (struct v4l2_control *)arg); + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; + } + + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; + } + return -EINVAL; + } + + case VIDIOC_G_STD: + *(v4l2_std_id *)arg = state->std; + break; + + case VIDIOC_S_STD: + if (state->radio == 0 && state->std == *(v4l2_std_id *)arg) + return 0; + state->radio = 0; + state->std = *(v4l2_std_id *)arg; + return set_v4lstd(cx); + + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->vid_input; + route->output = 0; + break; + + case VIDIOC_INT_S_VIDEO_ROUTING: + return set_input(cx, route->input, state->aud_input); + + case VIDIOC_INT_G_AUDIO_ROUTING: + route->input = state->aud_input; + route->output = 0; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + return set_input(cx, state->vid_input, route->input); + + case VIDIOC_S_FREQUENCY: + input_change(cx); + break; + + case VIDIOC_G_TUNER: + { + u8 vpres = cx18_av_read(cx, 0x40e) & 0x20; + u8 mode; + int val = 0; + + if (state->radio) + break; + + vt->signal = vpres ? 0xffff : 0x0; + + vt->capability |= + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + + mode = cx18_av_read(cx, 0x804); + + /* get rxsubchans and audmode */ + if ((mode & 0xf) == 1) + val |= V4L2_TUNER_SUB_STEREO; + else + val |= V4L2_TUNER_SUB_MONO; + + if (mode == 2 || mode == 4) + val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (mode & 0x10) + val |= V4L2_TUNER_SUB_SAP; + + vt->rxsubchans = val; + vt->audmode = state->audmode; + break; + } + + case VIDIOC_S_TUNER: + if (state->radio) + break; + + switch (vt->audmode) { + case V4L2_TUNER_MODE_MONO: + /* mono -> mono + stereo -> mono + bilingual -> lang1 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x00); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* mono -> mono + stereo -> stereo + bilingual -> lang1 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x04); + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang1/lang2 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x07); + break; + case V4L2_TUNER_MODE_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang2 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x01); + break; + default: + return -EINVAL; + } + state->audmode = vt->audmode; + break; + + case VIDIOC_G_FMT: + return get_v4lfmt(cx, (struct v4l2_format *)arg); + + case VIDIOC_S_FMT: + return set_v4lfmt(cx, (struct v4l2_format *)arg); + + case VIDIOC_INT_RESET: + cx18_av_initialize(cx); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------- */ + +static void log_video_status(struct cx18 *cx) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx18_av_state *state = &cx->av_state; + u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf; + u8 gen_stat1 = cx18_av_read(cx, 0x40d); + u8 gen_stat2 = cx18_av_read(cx, 0x40e); + int vid_input = state->vid_input; + + CX18_INFO("Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + CX18_INFO("Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + CX18_INFO("Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8) { + CX18_INFO("Specified video input: Composite %d\n", + vid_input - CX18_AV_COMPOSITE1 + 1); + } else { + CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 download_ctl = cx18_av_read(cx, 0x803); + u8 mod_det_stat0 = cx18_av_read(cx, 0x805); + u8 mod_det_stat1 = cx18_av_read(cx, 0x804); + u8 audio_config = cx18_av_read(cx, 0x808); + u8 pref_mode = cx18_av_read(cx, 0x809); + u8 afc0 = cx18_av_read(cx, 0x80b); + u8 mute_ctl = cx18_av_read(cx, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + CX18_INFO("Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "BTSC"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + CX18_INFO("Detected audio standard: %s\n", p); + CX18_INFO("Audio muted: %s\n", + (mute_ctl & 0x2) ? "yes" : "no"); + CX18_INFO("Audio microcontroller: %s\n", + (download_ctl & 0x10) ? "running" : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "BTSC"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio system: %s\n", p); + } + + if (aud_input) + CX18_INFO("Specified audio input: Tuner (In%d)\n", + aud_input); + else + CX18_INFO("Specified audio input: External\n"); + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + CX18_INFO("Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 2) & 0x1) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + } + CX18_INFO("Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x3) { + case 0: p = "BTSC"; break; + case 1: p = "EIAJ"; break; + case 2: p = "A2-M"; break; + default: p = "undefined"; + } + CX18_INFO("Selected 45 MHz format: %s\n", p); + } +} diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h new file mode 100644 index 000000000000..786901d72e9a --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -0,0 +1,318 @@ +/* + * cx18 ADEC header + * + * Derived from cx25840-core.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX18_AV_CORE_H_ +#define _CX18_AV_CORE_H_ + +struct cx18; + +enum cx18_av_video_input { + /* Composite video inputs In1-In8 */ + CX18_AV_COMPOSITE1 = 1, + CX18_AV_COMPOSITE2, + CX18_AV_COMPOSITE3, + CX18_AV_COMPOSITE4, + CX18_AV_COMPOSITE5, + CX18_AV_COMPOSITE6, + CX18_AV_COMPOSITE7, + CX18_AV_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX18_AV_SVIDEO_LUMA1 = 0x10, + CX18_AV_SVIDEO_LUMA2 = 0x20, + CX18_AV_SVIDEO_LUMA3 = 0x30, + CX18_AV_SVIDEO_LUMA4 = 0x40, + CX18_AV_SVIDEO_CHROMA4 = 0x400, + CX18_AV_SVIDEO_CHROMA5 = 0x500, + CX18_AV_SVIDEO_CHROMA6 = 0x600, + CX18_AV_SVIDEO_CHROMA7 = 0x700, + CX18_AV_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX18_AV_SVIDEO1 = 0x510, + CX18_AV_SVIDEO2 = 0x620, + CX18_AV_SVIDEO3 = 0x730, + CX18_AV_SVIDEO4 = 0x840, +}; + +enum cx18_av_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX18_AV_AUDIO_SERIAL, + CX18_AV_AUDIO4 = 4, + CX18_AV_AUDIO5, + CX18_AV_AUDIO6, + CX18_AV_AUDIO7, + CX18_AV_AUDIO8, +}; + +struct cx18_av_state { + int radio; + v4l2_std_id std; + enum cx18_av_video_input vid_input; + enum cx18_av_audio_input aud_input; + u32 audclk_freq; + int audmode; + int vbi_line_offset; + u32 id; + u32 rev; + int is_initialized; +}; + + +/* Registers */ +#define CXADEC_CHIP_TYPE_TIGER 0x837 +#define CXADEC_CHIP_TYPE_MAKO 0x843 + +#define CXADEC_HOST_REG1 0x000 +#define CXADEC_HOST_REG2 0x001 + +#define CXADEC_CHIP_CTRL 0x100 +#define CXADEC_AFE_CTRL 0x104 +#define CXADEC_PLL_CTRL1 0x108 +#define CXADEC_VID_PLL_FRAC 0x10C +#define CXADEC_AUX_PLL_FRAC 0x110 +#define CXADEC_PIN_CTRL1 0x114 +#define CXADEC_PIN_CTRL2 0x118 +#define CXADEC_PIN_CFG1 0x11C +#define CXADEC_PIN_CFG2 0x120 + +#define CXADEC_PIN_CFG3 0x124 +#define CXADEC_I2S_MCLK 0x127 + +#define CXADEC_AUD_LOCK1 0x128 +#define CXADEC_AUD_LOCK2 0x12C +#define CXADEC_POWER_CTRL 0x130 +#define CXADEC_AFE_DIAG_CTRL1 0x134 +#define CXADEC_AFE_DIAG_CTRL2 0x138 +#define CXADEC_AFE_DIAG_CTRL3 0x13C +#define CXADEC_PLL_DIAG_CTRL 0x140 +#define CXADEC_TEST_CTRL1 0x144 +#define CXADEC_TEST_CTRL2 0x148 +#define CXADEC_BIST_STAT 0x14C +#define CXADEC_DLL1_DIAG_CTRL 0x158 +#define CXADEC_DLL2_DIAG_CTRL 0x15C + +/* IR registers */ +#define CXADEC_IR_CTRL_REG 0x200 +#define CXADEC_IR_TXCLK_REG 0x204 +#define CXADEC_IR_RXCLK_REG 0x208 +#define CXADEC_IR_CDUTY_REG 0x20C +#define CXADEC_IR_STAT_REG 0x210 +#define CXADEC_IR_IRQEN_REG 0x214 +#define CXADEC_IR_FILTER_REG 0x218 +#define CXADEC_IR_FIFO_REG 0x21C + +/* Video Registers */ +#define CXADEC_MODE_CTRL 0x400 +#define CXADEC_OUT_CTRL1 0x404 +#define CXADEC_OUT_CTRL2 0x408 +#define CXADEC_GEN_STAT 0x40C +#define CXADEC_INT_STAT_MASK 0x410 +#define CXADEC_LUMA_CTRL 0x414 + +#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414 +#define CXADEC_CONTRAST_CTRL_BYTE 0x415 +#define CXADEC_LUMA_CTRL_BYTE_3 0x416 + +#define CXADEC_HSCALE_CTRL 0x418 +#define CXADEC_VSCALE_CTRL 0x41C + +#define CXADEC_CHROMA_CTRL 0x420 + +#define CXADEC_USAT_CTRL_BYTE 0x420 +#define CXADEC_VSAT_CTRL_BYTE 0x421 +#define CXADEC_HUE_CTRL_BYTE 0x422 + +#define CXADEC_VBI_LINE_CTRL1 0x424 +#define CXADEC_VBI_LINE_CTRL2 0x428 +#define CXADEC_VBI_LINE_CTRL3 0x42C +#define CXADEC_VBI_LINE_CTRL4 0x430 +#define CXADEC_VBI_LINE_CTRL5 0x434 +#define CXADEC_VBI_FC_CFG 0x438 +#define CXADEC_VBI_MISC_CFG1 0x43C +#define CXADEC_VBI_MISC_CFG2 0x440 +#define CXADEC_VBI_PAY1 0x444 +#define CXADEC_VBI_PAY2 0x448 +#define CXADEC_VBI_CUST1_CFG1 0x44C +#define CXADEC_VBI_CUST1_CFG2 0x450 +#define CXADEC_VBI_CUST1_CFG3 0x454 +#define CXADEC_VBI_CUST2_CFG1 0x458 +#define CXADEC_VBI_CUST2_CFG2 0x45C +#define CXADEC_VBI_CUST2_CFG3 0x460 +#define CXADEC_VBI_CUST3_CFG1 0x464 +#define CXADEC_VBI_CUST3_CFG2 0x468 +#define CXADEC_VBI_CUST3_CFG3 0x46C +#define CXADEC_HORIZ_TIM_CTRL 0x470 +#define CXADEC_VERT_TIM_CTRL 0x474 +#define CXADEC_SRC_COMB_CFG 0x478 +#define CXADEC_CHROMA_VBIOFF_CFG 0x47C +#define CXADEC_FIELD_COUNT 0x480 +#define CXADEC_MISC_TIM_CTRL 0x484 +#define CXADEC_DFE_CTRL1 0x488 +#define CXADEC_DFE_CTRL2 0x48C +#define CXADEC_DFE_CTRL3 0x490 +#define CXADEC_PLL_CTRL2 0x494 +#define CXADEC_HTL_CTRL 0x498 +#define CXADEC_COMB_CTRL 0x49C +#define CXADEC_CRUSH_CTRL 0x4A0 +#define CXADEC_SOFT_RST_CTRL 0x4A4 +#define CXADEC_MV_DT_CTRL2 0x4A8 +#define CXADEC_MV_DT_CTRL3 0x4AC +#define CXADEC_MISC_DIAG_CTRL 0x4B8 + +#define CXADEC_DL_CTL 0x800 +#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ +#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ +#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ +#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ + +#define CXADEC_STD_DET_STATUS 0x804 + +#define CXADEC_STD_DET_CTL 0x808 +#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ +#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ + +#define CXADEC_DW8051_INT 0x80C +#define CXADEC_GENERAL_CTL 0x810 +#define CXADEC_AAGC_CTL 0x814 +#define CXADEC_IF_SRC_CTL 0x818 +#define CXADEC_ANLOG_DEMOD_CTL 0x81C +#define CXADEC_ROT_FREQ_CTL 0x820 +#define CXADEC_FM1_CTL 0x824 +#define CXADEC_PDF_CTL 0x828 +#define CXADEC_DFT1_CTL1 0x82C +#define CXADEC_DFT1_CTL2 0x830 +#define CXADEC_DFT_STATUS 0x834 +#define CXADEC_DFT2_CTL1 0x838 +#define CXADEC_DFT2_CTL2 0x83C +#define CXADEC_DFT2_STATUS 0x840 +#define CXADEC_DFT3_CTL1 0x844 +#define CXADEC_DFT3_CTL2 0x848 +#define CXADEC_DFT3_STATUS 0x84C +#define CXADEC_DFT4_CTL1 0x850 +#define CXADEC_DFT4_CTL2 0x854 +#define CXADEC_DFT4_STATUS 0x858 +#define CXADEC_AM_MTS_DET 0x85C +#define CXADEC_ANALOG_MUX_CTL 0x860 +#define CXADEC_DIG_PLL_CTL1 0x864 +#define CXADEC_DIG_PLL_CTL2 0x868 +#define CXADEC_DIG_PLL_CTL3 0x86C +#define CXADEC_DIG_PLL_CTL4 0x870 +#define CXADEC_DIG_PLL_CTL5 0x874 +#define CXADEC_DEEMPH_GAIN_CTL 0x878 +#define CXADEC_DEEMPH_COEF1 0x87C +#define CXADEC_DEEMPH_COEF2 0x880 +#define CXADEC_DBX1_CTL1 0x884 +#define CXADEC_DBX1_CTL2 0x888 +#define CXADEC_DBX1_STATUS 0x88C +#define CXADEC_DBX2_CTL1 0x890 +#define CXADEC_DBX2_CTL2 0x894 +#define CXADEC_DBX2_STATUS 0x898 +#define CXADEC_AM_FM_DIFF 0x89C + +/* NICAM registers go here */ +#define CXADEC_NICAM_STATUS 0x8C8 +#define CXADEC_DEMATRIX_CTL 0x8CC + +#define CXADEC_PATH1_CTL1 0x8D0 +#define CXADEC_PATH1_VOL_CTL 0x8D4 +#define CXADEC_PATH1_EQ_CTL 0x8D8 +#define CXADEC_PATH1_SC_CTL 0x8DC + +#define CXADEC_PATH2_CTL1 0x8E0 +#define CXADEC_PATH2_VOL_CTL 0x8E4 +#define CXADEC_PATH2_EQ_CTL 0x8E8 +#define CXADEC_PATH2_SC_CTL 0x8EC + +#define CXADEC_SRC_CTL 0x8F0 +#define CXADEC_SRC_LF_COEF 0x8F4 +#define CXADEC_SRC1_CTL 0x8F8 +#define CXADEC_SRC2_CTL 0x8FC +#define CXADEC_SRC3_CTL 0x900 +#define CXADEC_SRC4_CTL 0x904 +#define CXADEC_SRC5_CTL 0x908 +#define CXADEC_SRC6_CTL 0x90C + +#define CXADEC_BASEBAND_OUT_SEL 0x910 +#define CXADEC_I2S_IN_CTL 0x914 +#define CXADEC_I2S_OUT_CTL 0x918 +#define CXADEC_AC97_CTL 0x91C +#define CXADEC_QAM_PDF 0x920 +#define CXADEC_QAM_CONST_DEC 0x924 +#define CXADEC_QAM_ROTATOR_FREQ 0x948 + +/* Bit defintions / settings used in Mako Audio */ +#define CXADEC_PREF_MODE_MONO_LANGA 0 +#define CXADEC_PREF_MODE_MONO_LANGB 1 +#define CXADEC_PREF_MODE_MONO_LANGC 2 +#define CXADEC_PREF_MODE_FALLBACK 3 +#define CXADEC_PREF_MODE_STEREO 4 +#define CXADEC_PREF_MODE_DUAL_LANG_AC 5 +#define CXADEC_PREF_MODE_DUAL_LANG_BC 6 +#define CXADEC_PREF_MODE_DUAL_LANG_AB 7 + + +#define CXADEC_DETECT_STEREO 1 +#define CXADEC_DETECT_DUAL 2 +#define CXADEC_DETECT_TRI 4 +#define CXADEC_DETECT_SAP 0x10 +#define CXADEC_DETECT_NO_SIGNAL 0xFF + +#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2 +#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3 +#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */ +#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */ +#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6 +#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7 +#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */ +#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ +#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ + +/* ----------------------------------------------------------------------- */ +/* cx18_av-core.c */ +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); +u8 cx18_av_read(struct cx18 *cx, u16 addr); +u32 cx18_av_read4(struct cx18 *cx, u16 addr); +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); +int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-firmware.c */ +int cx18_av_loadfw(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-audio.c */ +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg); +void cx18_av_audio_set_path(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-vbi.c */ +void cx18_av_vbi_setup(struct cx18 *cx); +int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg); + +#endif diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c new file mode 100644 index 000000000000..526e142156cd --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -0,0 +1,120 @@ +/* + * cx18 ADEC firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" +#include <linux/firmware.h> + +#define FWFILE "v4l-cx23418-dig.fw" + +int cx18_av_loadfw(struct cx18 *cx) +{ + const struct firmware *fw = NULL; + u32 size; + u32 v; + u8 *ptr; + int i; + + if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { + CX18_ERR("unable to open firmware %s\n", FWFILE); + return -EINVAL; + } + + cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); + cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */ + + /* Reset the Mako core (Register is undocumented.) */ + cx18_av_write4(cx, 0x8100, 0x00010000); + + /* Put the 8051 in reset and enable firmware upload */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); + + ptr = fw->data; + size = fw->size; + + for (i = 0; i < size; i++) { + u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16); + u32 value = 0; + int retries; + + for (retries = 0; retries < 5; retries++) { + cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); + value = cx18_av_read4(cx, CXADEC_DL_CTL); + if ((value & 0x3F00) == (dl_control & 0x3F00)) + break; + } + if (retries >= 5) { + CX18_ERR("unable to load firmware %s\n", FWFILE); + release_firmware(fw); + return -EIO; + } + } + + cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); + + /* Output to the 416 */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); + + /* Audio input control 1 set to Sony mode */ + /* Audio output input 2 is 0 for slave operation input */ + /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); + + /* Audio output control 1 is set to Sony mode */ + /* Audio output control 2 is set to 1 for master mode */ + /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT + are generated) */ + cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); + + /* set alt I2s master clock to /16 and enable alt divider i2s + passthrough */ + cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); + + cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6); + /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ + + /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ + /* Register 0x09CC is defined by the Merlin firmware, and doesn't + have a name in the spec. */ + cx18_av_write4(cx, 0x09CC, 1); + +#define CX18_AUDIO_ENABLE 0xc72014 + v = read_reg(CX18_AUDIO_ENABLE); + /* If bit 11 is 1 */ + if (v & 0x800) + write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */ + + /* Enable WW auto audio standard detection */ + v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); + v |= 0xFF; /* Auto by default */ + v |= 0x400; /* Stereo by default */ + v |= 0x14000000; + cx18_av_write4(cx, CXADEC_STD_DET_CTL, v); + + release_firmware(fw); + + CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c new file mode 100644 index 000000000000..d09f1daf4ebf --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-vbi.c @@ -0,0 +1,413 @@ +/* + * cx18 ADEC VBI functions + * + * Derived from cx25840-vbi.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include "cx18-driver.h" + +static int odd_parity(u8 c) +{ + c ^= (c >> 4); + c ^= (c >> 2); + c ^= (c >> 1); + + return c & 1; +} + +static int decode_vps(u8 *dst, u8 *p) +{ + static const u8 biphase_tbl[] = { + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, + 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, + 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, + 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, + 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, + 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, + 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + }; + + u8 c, err = 0; + int i; + + for (i = 0; i < 2 * 13; i += 2) { + err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; + c = (biphase_tbl[p[i + 1]] & 0xf) | + ((biphase_tbl[p[i]] & 0xf) << 4); + dst[i / 2] = c; + } + + return err & 0xf0; +} + +void cx18_av_vbi_setup(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656, src_decimation; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx18_av_write(cx, 0x49f, 0x11); + else + cx18_av_write(cx, 0x49f, 0x14); + + if (std & V4L2_STD_625_50) { + hblank = 0x084; + hactive = 0x2d0; + burst = 0x5d; + vblank = 0x024; + vactive = 0x244; + vblank656 = 0x28; + src_decimation = 0x21f; + + luma_lpf = 2; + if (std & V4L2_STD_SECAM) { + uv_lpf = 0; + comb = 0; + sc = 0x0a425f; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + sc = 556453; + } else { + uv_lpf = 1; + comb = 0x20; + sc = 0x0a8263; + } + } else { + hactive = 720; + hblank = 122; + vactive = 487; + luma_lpf = 1; + uv_lpf = 1; + + src_decimation = 0x21f; + if (std == V4L2_STD_PAL_60) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + luma_lpf = 2; + comb = 0x20; + sc = 0x0a8263; + } else if (std == V4L2_STD_PAL_M) { + vblank = 20; + vblank656 = 24; + burst = 0x61; + comb = 0x20; + + sc = 555452; + } else { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + comb = 0x66; + sc = 556063; + } + } + + /* DEBUG: Displays configured PLL frequency */ + pll_int = cx18_av_read(cx, 0x108); + pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; + pll_post = cx18_av_read(cx, 0x109); + CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fin, fsc; + int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac); + + pll >>= 25; + pll /= pll_post; + CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); + + fin = ((u64)src_decimation * pll) >> 12; + CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); + + fsc = (((u64)sc) * pll) >> 24L; + CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); + + CX18_DEBUG_INFO("hblank %i, hactive %i, " + "vblank %i , vactive %i, vblank656 %i, src_dec %i," + "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," + " sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + } + + /* Sets horizontal blanking delay and active lines */ + cx18_av_write(cx, 0x470, hblank); + cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | + (hactive << 4))); + cx18_av_write(cx, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx18_av_write(cx, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx18_av_write(cx, 0x474, vblank); + cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | + (vactive << 4))); + cx18_av_write(cx, 0x476, vactive >> 4); + cx18_av_write(cx, 0x477, vblank656); + + /* Sets src decimation rate */ + cx18_av_write(cx, 0x478, 0xff & src_decimation); + cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx18_av_write(cx, 0x47b, comb); + + /* Sets SC Step*/ + cx18_av_write(cx, 0x47c, sc); + cx18_av_write(cx, 0x47d, 0xff & sc >> 8); + cx18_av_write(cx, 0x47e, 0xff & sc >> 16); + + /* Sets VBI parameters */ + if (std & V4L2_STD_625_50) { + cx18_av_write(cx, 0x47f, 0x01); + state->vbi_line_offset = 5; + } else { + cx18_av_write(cx, 0x47f, 0x00); + state->vbi_line_offset = 8; + } +} + +int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_format *fmt; + struct v4l2_sliced_vbi_format *svbi; + + switch (cmd) { + case VIDIOC_G_FMT: + { + static u16 lcr2vbi[] = { + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_WSS_625, 0, /* 4 */ + V4L2_SLICED_CAPTION_525, /* 6 */ + 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ + 0, 0, 0, 0 + }; + int is_pal = !(state->std & V4L2_STD_525_60); + int i; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + memset(svbi, 0, sizeof(*svbi)); + /* we're done if raw VBI is active */ + if ((cx18_av_read(cx, 0x404) & 0x10) == 0) + break; + + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } else { + for (i = 10; i <= 21; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 10); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } + break; + } + + case VIDIOC_S_FMT: + { + int is_pal = !(state->std & V4L2_STD_525_60); + int vbi_offset = is_pal ? 1 : 0; + int i, x; + u8 lcr[24]; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + if (svbi->service_set == 0) { + /* raw VBI */ + memset(svbi, 0, sizeof(*svbi)); + + /* Setup VBI */ + cx18_av_vbi_setup(cx); + + /* VBI Offset */ + cx18_av_write(cx, 0x47f, vbi_offset); + cx18_av_write(cx, 0x404, 0x2e); + break; + } + + for (x = 0; x <= 23; x++) + lcr[x] = 0x00; + + /* Setup VBI */ + cx18_av_vbi_setup(cx); + + /* Sliced VBI */ + cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ + cx18_av_write(cx, 0x406, 0x13); + cx18_av_write(cx, 0x47f, vbi_offset); + + if (is_pal) { + for (i = 0; i <= 6; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } else { + for (i = 0; i <= 9; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + + for (i = 22; i <= 23; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } + + for (i = 7; i <= 23; i++) { + for (x = 0; x <= 1; x++) { + switch (svbi->service_lines[1-x][i]) { + case V4L2_SLICED_TELETEXT_B: + lcr[i] |= 1 << (4 * x); + break; + case V4L2_SLICED_WSS_625: + lcr[i] |= 4 << (4 * x); + break; + case V4L2_SLICED_CAPTION_525: + lcr[i] |= 6 << (4 * x); + break; + case V4L2_SLICED_VPS: + lcr[i] |= 9 << (4 * x); + break; + } + } + } + + if (is_pal) { + for (x = 1, i = 0x424; i <= 0x434; i++, x++) + cx18_av_write(cx, i, lcr[6 + x]); + } else { + for (x = 1, i = 0x424; i <= 0x430; i++, x++) + cx18_av_write(cx, i, lcr[9 + x]); + for (i = 0x431; i <= 0x434; i++) + cx18_av_write(cx, i, 0); + } + + cx18_av_write(cx, 0x43c, 0x16); + cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22); + break; + } + + case VIDIOC_INT_DECODE_VBI_LINE: + { + struct v4l2_decode_vbi_line *vbi = arg; + u8 *p = vbi->p; + int id1, id2, l, err = 0; + + if (p[0] || p[1] != 0xff || p[2] != 0xff || + (p[3] != 0x55 && p[3] != 0x91)) { + vbi->line = vbi->type = 0; + break; + } + + p += 4; + id1 = p[-1]; + id2 = p[0] & 0xf; + l = p[2] & 0x3f; + l += state->vbi_line_offset; + p += 4; + + switch (id2) { + case 1: + id2 = V4L2_SLICED_TELETEXT_B; + break; + case 4: + id2 = V4L2_SLICED_WSS_625; + break; + case 6: + id2 = V4L2_SLICED_CAPTION_525; + err = !odd_parity(p[0]) || !odd_parity(p[1]); + break; + case 9: + id2 = V4L2_SLICED_VPS; + if (decode_vps(p, p) != 0) + err = 1; + break; + default: + id2 = 0; + err = 1; + break; + } + + vbi->type = err ? 0 : id2; + vbi->line = err ? 0 : l; + vbi->is_second_field = err ? 0 : (id1 == 0x55); + vbi->p = p; + break; + } + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c new file mode 100644 index 000000000000..f5e3ba1f5354 --- /dev/null +++ b/drivers/media/video/cx18/cx18-cards.c @@ -0,0 +1,277 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include <media/cs5345.h> + +/********************** card configuration *******************************/ + +/* usual i2c tuner addresses to probe */ +static struct cx18_card_tuner_i2c cx18_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii + This keeps the PCI ID database up to date. Note that the entries + must be added under vendor 0x4444 (Conexant) as subsystem IDs. + New vendor IDs should still be added to the vendor ID list. */ + +/* Hauppauge HVR-1600 cards */ + +/* Note: for Hauppauge cards the tveeprom information is used instead + of PCI IDs */ +static const struct cx18_card cx18_card_hvr1600_esmt = { + .type = CX18_CARD_HVR_1600_ESMT, + .name = "Hauppauge HVR-1600", + .comment = "DVB & VBI are not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .ddr = { + /* ESMT M13S128324A-5B memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x44220e82, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card cx18_card_hvr1600_samsung = { + .type = CX18_CARD_HVR_1600_SAMSUNG, + .name = "Hauppauge HVR-1600 (Preproduction)", + .comment = "DVB & VBI are not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .ddr = { + /* Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Compro VideoMate H900: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_h900[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_h900 = { + .type = CX18_CARD_COMPRO_H900, + .name = "Compro VideoMate H900", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .ddr = { + /* EtronTech EM6A9160TS-5G memory */ + .chip_config = 0x50003, + .refresh = 0x753, + .timing1 = 0x24330e84, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0, + }, + .pci_list = cx18_pci_h900, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPC718: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_mpc718[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_mpc718 = { + .type = CX18_CARD_YUAN_MPC718, + .name = "Yuan MPC718", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + /* tuner reset */ + .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, + .ddr = { + /* Probably Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .pci_list = cx18_pci_mpc718, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card *cx18_card_list[] = { + &cx18_card_hvr1600_esmt, + &cx18_card_hvr1600_samsung, + &cx18_card_h900, + &cx18_card_mpc718, +}; + +const struct cx18_card *cx18_get_card(u16 index) +{ + if (index >= ARRAY_SIZE(cx18_card_list)) + return NULL; + return cx18_card_list[index]; +} + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input) +{ + const struct cx18_card_video_input *card_input = + cx->card->video_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "S-Video 1", + "S-Video 2", + "Composite 1", + "Composite 2", + "Composite 3" + }; + + memset(input, 0, sizeof(*input)); + if (index >= cx->nof_inputs) + return -EINVAL; + input->index = index; + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); + input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ? + V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); + input->audioset = (1 << cx->nof_audio_inputs) - 1; + input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? + cx->tuner_std : V4L2_STD_ALL; + return 0; +} + +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio) +{ + const struct cx18_card_audio_input *aud_input = + cx->card->audio_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "Line In 1", + "Line In 2" + }; + + memset(audio, 0, sizeof(*audio)); + if (index >= cx->nof_audio_inputs) + return -EINVAL; + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); + audio->index = index; + audio->capability = V4L2_AUDCAP_STEREO; + return 0; +} diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h new file mode 100644 index 000000000000..bca249bdd337 --- /dev/null +++ b/drivers/media/video/cx18/cx18-cards.h @@ -0,0 +1,170 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* hardware flags */ +#define CX18_HW_TUNER (1 << 0) +#define CX18_HW_TVEEPROM (1 << 1) +#define CX18_HW_CS5345 (1 << 2) +#define CX18_HW_GPIO (1 << 3) +#define CX18_HW_CX23418 (1 << 4) +#define CX18_HW_DVB (1 << 5) + +/* video inputs */ +#define CX18_CARD_INPUT_VID_TUNER 1 +#define CX18_CARD_INPUT_SVIDEO1 2 +#define CX18_CARD_INPUT_SVIDEO2 3 +#define CX18_CARD_INPUT_COMPOSITE1 4 +#define CX18_CARD_INPUT_COMPOSITE2 5 +#define CX18_CARD_INPUT_COMPOSITE3 6 + +enum cx34180_video_input { + /* Composite video inputs In1-In8 */ + CX23418_COMPOSITE1 = 1, + CX23418_COMPOSITE2, + CX23418_COMPOSITE3, + CX23418_COMPOSITE4, + CX23418_COMPOSITE5, + CX23418_COMPOSITE6, + CX23418_COMPOSITE7, + CX23418_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX23418_SVIDEO_LUMA1 = 0x10, + CX23418_SVIDEO_LUMA2 = 0x20, + CX23418_SVIDEO_LUMA3 = 0x30, + CX23418_SVIDEO_LUMA4 = 0x40, + CX23418_SVIDEO_CHROMA4 = 0x400, + CX23418_SVIDEO_CHROMA5 = 0x500, + CX23418_SVIDEO_CHROMA6 = 0x600, + CX23418_SVIDEO_CHROMA7 = 0x700, + CX23418_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX23418_SVIDEO1 = 0x510, + CX23418_SVIDEO2 = 0x620, + CX23418_SVIDEO3 = 0x730, + CX23418_SVIDEO4 = 0x840, +}; + +/* audio inputs */ +#define CX18_CARD_INPUT_AUD_TUNER 1 +#define CX18_CARD_INPUT_LINE_IN1 2 +#define CX18_CARD_INPUT_LINE_IN2 3 + +#define CX18_CARD_MAX_VIDEO_INPUTS 6 +#define CX18_CARD_MAX_AUDIO_INPUTS 3 +#define CX18_CARD_MAX_TUNERS 2 + +enum cx23418_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX23418_AUDIO_SERIAL, + CX23418_AUDIO4 = 4, + CX23418_AUDIO5, + CX23418_AUDIO6, + CX23418_AUDIO7, + CX23418_AUDIO8, +}; + +/* V4L2 capability aliases */ +#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE) +/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ + +struct cx18_card_video_input { + u8 video_type; /* video input type */ + u8 audio_index; /* index in cx18_card_audio_input array */ + u16 video_input; /* hardware video input */ +}; + +struct cx18_card_audio_input { + u8 audio_type; /* audio input type */ + u32 audio_input; /* hardware audio input */ + u16 muxer_input; /* hardware muxer input for boards with a + multiplexer chip */ +}; + +struct cx18_card_pci_info { + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; +}; + +/* GPIO definitions */ + +/* The mask is the set of bits used by the operation */ + +struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ + u16 direction; /* DIR setting. Leave to 0 if no init is needed */ + u16 initial_value; +}; + +struct cx18_card_tuner { + v4l2_std_id std; /* standard for which the tuner is suitable */ + int tuner; /* tuner ID (from tuner.h) */ +}; + +struct cx18_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[2];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + +struct cx18_ddr { /* DDR config data */ + u32 chip_config; + u32 refresh; + u32 timing1; + u32 timing2; + u32 tune_lane; + u32 initial_emrs; +}; + +/* for card information/parameters */ +struct cx18_card { + int type; + char *name; + char *comment; + u32 v4l2_capabilities; + u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only + 1 dev allowed) */ + u32 hw_muxer; /* hardware used to multiplex audio input */ + u32 hw_all; /* all hardware used by the board */ + struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; + struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS]; + struct cx18_card_audio_input radio_input; + + /* GPIO card-specific settings */ + struct cx18_gpio_init gpio_init; + + struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; + struct cx18_card_tuner_i2c *i2c; + + struct cx18_ddr ddr; + + /* list of device and subsystem vendor/devices that + correspond to this card type. */ + const struct cx18_card_pci_info *pci_list; +}; + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input); +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input); +const struct cx18_card *cx18_get_card(u16 index); diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c new file mode 100644 index 000000000000..2bdac5ebbb0d --- /dev/null +++ b/drivers/media/video/cx18/cx18-controls.c @@ -0,0 +1,306 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-av-core.h" +#include "cx18-cards.h" +#include "cx18-ioctl.h" +#include "cx18-audio.h" +#include "cx18-i2c.h" +#include "cx18-mailbox.h" +#include "cx18-controls.h" + +static const u32 user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_BALANCE, + V4L2_CID_AUDIO_BASS, + V4L2_CID_AUDIO_TREBLE, + V4L2_CID_AUDIO_MUTE, + V4L2_CID_AUDIO_LOUDNESS, + 0 +}; + +static const u32 *ctrl_classes[] = { + user_ctrls, + cx2341x_mpeg_ctrls, + NULL +}; + +static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) +{ + const char *name; + + CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); + + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (qctrl->id == 0) + return -EINVAL; + + switch (qctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + default: + if (cx2341x_ctrl_query(&cx->params, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + } + strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); + qctrl->name[sizeof(qctrl->name) - 1] = 0; + return 0; +} + +static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu) +{ + struct v4l2_queryctrl qctrl; + + qctrl.id = qmenu->id; + cx18_queryctrl(cx, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); +} + +static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ + s32 v = vctrl->value; + + CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); + + switch (vctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl); + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); + + default: + CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + return -EINVAL; + } + return 0; +} + +static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ + CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); + + switch (vctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl); + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); + default: + CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + return -EINVAL; + } + return 0; +} + +static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt) +{ + if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) + return -EINVAL; + if (atomic_read(&cx->capturing) > 0) + return -EBUSY; + + /* First try to allocate sliced VBI buffers if needed. */ + if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) { + int i; + + for (i = 0; i < CX18_VBI_FRAMES; i++) { + /* Yuck, hardcoded. Needs to be a define */ + cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); + if (cx->vbi.sliced_mpeg_data[i] == NULL) { + while (--i >= 0) { + kfree(cx->vbi.sliced_mpeg_data[i]); + cx->vbi.sliced_mpeg_data[i] = NULL; + } + return -ENOMEM; + } + } + } + + cx->vbi.insert_mpeg = fmt; + + if (cx->vbi.insert_mpeg == 0) + return 0; + /* Need sliced data for mpeg insertion */ + if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { + if (cx->is_60hz) + cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; + else + cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; + cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); + } + return 0; +} + +int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_control ctrl; + + switch (cmd) { + case VIDIOC_QUERYMENU: + CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); + return cx18_querymenu(cx, arg); + + case VIDIOC_QUERYCTRL: + return cx18_queryctrl(cx, arg); + + case VIDIOC_S_CTRL: + return cx18_s_ctrl(cx, arg); + + case VIDIOC_G_CTRL: + return cx18_g_ctrl(cx, arg); + + case VIDIOC_S_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_s_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; + } + } + return err; + } + CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + struct cx2341x_mpeg_params p = cx->params; + int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd); + + if (err) + return err; + + if (p.video_encoding != cx->params.video_encoding) { + int is_mpeg1 = p.video_encoding == + V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_format fmt; + + /* fix videodecoder resolution */ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1); + fmt.fmt.pix.height = cx->params.height; + cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); + } + err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); + if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) + err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); + cx->params = p; + cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; + cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); + return err; + } + return -EINVAL; + } + + case VIDIOC_G_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_g_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; + } + } + return err; + } + CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd); + return -EINVAL; + } + + case VIDIOC_TRY_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, + atomic_read(&cx->capturing), arg, cmd); + return -EINVAL; + } + + default: + return -EINVAL; + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h new file mode 100644 index 000000000000..6e985cf422a0 --- /dev/null +++ b/drivers/media/video/cx18/cx18-controls.h @@ -0,0 +1,24 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c new file mode 100644 index 000000000000..8f5ed9b4bf83 --- /dev/null +++ b/drivers/media/video/cx18/cx18-driver.c @@ -0,0 +1,971 @@ +/* + * cx18 driver initialization and card probing + * + * Derived from ivtv-driver.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include "cx18-irq.h" +#include "cx18-gpio.h" +#include "cx18-firmware.h" +#include "cx18-streams.h" +#include "cx18-av-core.h" +#include "cx18-scb.h" +#include "cx18-mailbox.h" +#include "cx18-ioctl.h" +#include "tuner-xc2028.h" + +#include <media/tveeprom.h> + + +/* var to keep track of the number of array elements in use */ +int cx18_cards_active; + +/* If you have already X v4l cards, then set this to X. This way + the device numbers stay matched. Example: you have a WinTV card + without radio and a Compro H900 with. Normally this would give a + video1 device together with a radio0 device for the Compro. By + setting this to 1 you ensure that radio0 is now also radio1. */ +int cx18_first_minor; + +/* Master variable for all cx18 info */ +struct cx18 *cx18_cards[CX18_MAX_CARDS]; + +/* Protects cx18_cards_active */ +DEFINE_SPINLOCK(cx18_cards_lock); + +/* add your revision and whatnot here */ +static struct pci_device_id cx18_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); + +/* Parameter declarations */ +static int cardtype[CX18_MAX_CARDS]; +static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + +static int cardtype_c = 1; +static int tuner_c = 1; +static int radio_c = 1; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +/* Buffers */ +static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; +static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; +static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; +static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; +static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; + +static int cx18_pci_latency = 1; + +int cx18_debug; + +module_param_array(tuner, int, &tuner_c, 0644); +module_param_array(radio, bool, &radio_c, 0644); +module_param_array(cardtype, int, &cardtype_c, 0644); +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); +module_param_named(debug, cx18_debug, int, 0644); +module_param(cx18_pci_latency, int, 0644); +module_param(cx18_first_minor, int, 0644); + +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_ts_buffers, int, 0644); +module_param(enc_yuv_buffers, int, 0644); +module_param(enc_vbi_buffers, int, 0644); +module_param(enc_pcm_buffers, int, 0644); + +MODULE_PARM_DESC(tuner, "Tuner type selection,\n" + "\t\t\tsee tuner.h for values"); +MODULE_PARM_DESC(radio, + "Enable or disable the radio. Use only if autodetection\n" + "\t\t\tfails. 0 = disable, 1 = enable"); +MODULE_PARM_DESC(cardtype, + "Only use this option if your card is not detected properly.\n" + "\t\tSpecify card type:\n" + "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" + "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" + "\t\t\t 3 = Compro VideoMate H900\n" + "\t\t\t 4 = Yuan MPC718\n" + "\t\t\t 0 = Autodetect (default)\n" + "\t\t\t-1 = Ignore this card\n\t\t"); +MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); +MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); +MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: dma\n" + "\t\t\t 16/0x0010: ioctl\n" + "\t\t\t 32/0x0020: file\n" + "\t\t\t 64/0x0040: i2c\n" + "\t\t\t128/0x0080: irq\n" + "\t\t\t256/0x0100: high volume\n"); +MODULE_PARM_DESC(cx18_pci_latency, + "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" + "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_ts_buffers, + "Encoder TS Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_buffers, + "Encoder YUV Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_buffers, + "Encoder VBI Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_buffers, + "Encoder PCM buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); + +MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card"); + +MODULE_AUTHOR("Hans Verkuil"); +MODULE_DESCRIPTION("CX23418 driver"); +MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); +MODULE_LICENSE("GPL"); + +MODULE_VERSION(CX18_VERSION); + +int cx18_waitq(wait_queue_head_t *waitq) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(waitq, &wait); + return signal_pending(current) ? -EINTR : 0; +} + +/* Generic utility functions */ +int cx18_msleep_timeout(unsigned int msecs, int intr) +{ + int timeout = msecs_to_jiffies(msecs); + int sig; + + do { + set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + sig = intr ? signal_pending(current) : 0; + } while (!sig && timeout); + return sig; +} + +/* Release ioremapped memory */ +static void cx18_iounmap(struct cx18 *cx) +{ + if (cx == NULL) + return; + + /* Release io memory */ + if (cx->enc_mem != NULL) { + CX18_DEBUG_INFO("releasing enc_mem\n"); + iounmap(cx->enc_mem); + cx->enc_mem = NULL; + } +} + +/* Hauppauge card? get values from tveeprom */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) +{ + u8 eedata[256]; + + cx->i2c_client[0].addr = 0xA0 >> 1; + tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata)); + tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata); +} + +static void cx18_process_eeprom(struct cx18 *cx) +{ + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + + /* Many thanks to Steven Toth from Hauppauge for providing the + model numbers */ + switch (tv.model) { + case 74000 ... 74099: + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + case 74700 ... 74799: + cx->card = cx18_get_card(CX18_CARD_HVR_1600_SAMSUNG); + break; + case 0: + CX18_ERR("Invalid EEPROM\n"); + return; + default: + CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model); + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + } + + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; + + CX18_INFO("Autodetected %s\n", cx->card_name); + + if (tv.tuner_type == TUNER_ABSENT) + CX18_ERR("tveeprom cannot autodetect tuner!"); + + if (cx->options.tuner == -1) + cx->options.tuner = tv.tuner_type; + if (cx->options.radio == -1) + cx->options.radio = (tv.has_radio != 0); + + if (cx->std != 0) + /* user specified tuner standard */ + return; + + /* autodetect tuner standard */ + if (tv.tuner_formats & V4L2_STD_PAL) { + CX18_DEBUG_INFO("PAL tuner detected\n"); + cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + } else if (tv.tuner_formats & V4L2_STD_NTSC) { + CX18_DEBUG_INFO("NTSC tuner detected\n"); + cx->std |= V4L2_STD_NTSC_M; + } else if (tv.tuner_formats & V4L2_STD_SECAM) { + CX18_DEBUG_INFO("SECAM tuner detected\n"); + cx->std |= V4L2_STD_SECAM_L; + } else { + CX18_INFO("No tuner detected, default to NTSC-M\n"); + cx->std |= V4L2_STD_NTSC_M; + } +} + +static v4l2_std_id cx18_parse_std(struct cx18 *cx) +{ + switch (pal[0]) { + case '6': + return V4L2_STD_PAL_60; + case 'b': + case 'B': + case 'g': + case 'G': + return V4L2_STD_PAL_BG; + case 'h': + case 'H': + return V4L2_STD_PAL_H; + case 'n': + case 'N': + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; + case 'i': + case 'I': + return V4L2_STD_PAL_I; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_PAL_DK; + case 'M': + case 'm': + return V4L2_STD_PAL_M; + case '-': + break; + default: + CX18_WARN("pal= argument not recognised\n"); + return 0; + } + + switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_SECAM_DK; + case 'l': + case 'L': + if (secam[1] == 'C' || secam[1] == 'c') + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; + case '-': + break; + default: + CX18_WARN("secam= argument not recognised\n"); + return 0; + } + + switch (ntsc[0]) { + case 'm': + case 'M': + return V4L2_STD_NTSC_M; + case 'j': + case 'J': + return V4L2_STD_NTSC_M_JP; + case 'k': + case 'K': + return V4L2_STD_NTSC_M_KR; + case '-': + break; + default: + CX18_WARN("ntsc= argument not recognised\n"); + return 0; + } + + /* no match found */ + return 0; +} + +static void cx18_process_options(struct cx18 *cx) +{ + int i, j; + + cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + cx->options.cardtype = cardtype[cx->num]; + cx->options.tuner = tuner[cx->num]; + cx->options.radio = radio[cx->num]; + + cx->std = cx18_parse_std(cx); + if (cx->options.cardtype == -1) { + CX18_INFO("Ignore card\n"); + return; + } + cx->card = cx18_get_card(cx->options.cardtype - 1); + if (cx->card) + CX18_INFO("User specified %s card\n", cx->card->name); + else if (cx->options.cardtype != 0) + CX18_ERR("Unknown user specified type, trying to autodetect card\n"); + if (cx->card == NULL) { + if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_INFO("Autodetected Hauppauge card\n"); + } + } + if (cx->card == NULL) { + for (i = 0; (cx->card = cx18_get_card(i)); i++) { + if (cx->card->pci_list == NULL) + continue; + for (j = 0; cx->card->pci_list[j].device; j++) { + if (cx->dev->device != + cx->card->pci_list[j].device) + continue; + if (cx->dev->subsystem_vendor != + cx->card->pci_list[j].subsystem_vendor) + continue; + if (cx->dev->subsystem_device != + cx->card->pci_list[j].subsystem_device) + continue; + CX18_INFO("Autodetected %s card\n", cx->card->name); + goto done; + } + } + } +done: + + if (cx->card == NULL) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_ERR("Unknown card: vendor/device: %04x/%04x\n", + cx->dev->vendor, cx->dev->device); + CX18_ERR(" subsystem vendor/device: %04x/%04x\n", + cx->dev->subsystem_vendor, cx->dev->subsystem_device); + CX18_ERR("Defaulting to %s card\n", cx->card->name); + CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); + CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); + CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); + } + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; +} + +/* Precondition: the cx18 structure has been memset to 0. Only + the dev and num fields have been filled in. + No assumptions on the card type may be made here (see cx18_init_struct2 + for that). + */ +static int __devinit cx18_init_struct1(struct cx18 *cx) +{ + cx->base_addr = pci_resource_start(cx->dev, 0); + + mutex_init(&cx->serialize_lock); + mutex_init(&cx->i2c_bus_lock[0]); + mutex_init(&cx->i2c_bus_lock[1]); + + spin_lock_init(&cx->lock); + spin_lock_init(&cx->dma_reg_lock); + + /* start counting open_id at 1 */ + cx->open_id = 1; + + /* Initial settings */ + cx2341x_fill_defaults(&cx->params); + cx->temporal_strength = cx->params.video_temporal_filter; + cx->spatial_strength = cx->params.video_spatial_filter; + cx->filter_mode = cx->params.video_spatial_filter_mode | + (cx->params.video_temporal_filter_mode << 1) | + (cx->params.video_median_filter_type << 2); + cx->params.port = CX2341X_PORT_MEMORY; + cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; + init_waitqueue_head(&cx->cap_w); + init_waitqueue_head(&cx->mb_apu_waitq); + init_waitqueue_head(&cx->mb_cpu_waitq); + init_waitqueue_head(&cx->mb_epu_waitq); + init_waitqueue_head(&cx->mb_hpu_waitq); + init_waitqueue_head(&cx->dma_waitq); + + /* VBI */ + cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; + cx->vbi.raw_size = 1456; + cx->vbi.raw_decoder_line_size = 1456; + cx->vbi.raw_decoder_sav_odd_field = 0x20; + cx->vbi.raw_decoder_sav_even_field = 0x60; + cx->vbi.sliced_decoder_line_size = 272; + cx->vbi.sliced_decoder_sav_odd_field = 0xB0; + cx->vbi.sliced_decoder_sav_even_field = 0xF0; + return 0; +} + +/* Second initialization part. Here the card type has been + autodetected. */ +static void __devinit cx18_init_struct2(struct cx18 *cx) +{ + int i; + + for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) + if (cx->card->video_inputs[i].video_type == 0) + break; + cx->nof_inputs = i; + for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) + if (cx->card->audio_inputs[i].audio_type == 0) + break; + cx->nof_audio_inputs = i; + + /* Find tuner input */ + for (i = 0; i < cx->nof_inputs; i++) { + if (cx->card->video_inputs[i].video_type == + CX18_CARD_INPUT_VID_TUNER) + break; + } + if (i == cx->nof_inputs) + i = 0; + cx->active_input = i; + cx->audio_input = cx->card->video_inputs[i].audio_index; + cx->av_state.vid_input = CX18_AV_COMPOSITE7; + cx->av_state.aud_input = CX18_AV_AUDIO8; + cx->av_state.audclk_freq = 48000; + cx->av_state.audmode = V4L2_TUNER_MODE_LANG1; + cx->av_state.vbi_line_offset = 8; +} + +static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + u16 cmd; + unsigned char pci_latency; + + CX18_DEBUG_INFO("Enabling pci device\n"); + + if (pci_enable_device(dev)) { + CX18_ERR("Can't enable device %d!\n", cx->num); + return -EIO; + } + if (pci_set_dma_mask(dev, 0xffffffff)) { + CX18_ERR("No suitable DMA available on card %d.\n", cx->num); + return -EIO; + } + if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { + CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num); + return -EIO; + } + + /* Check for bus mastering */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, cmd); + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 64 && cx18_pci_latency) { + CX18_INFO("Unreasonably low latency timer, " + "setting to 64 (was %d)\n", pci_latency); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + } + /* This config space value relates to DMA latencies. The + default value 0x8080 is too low however and will lead + to DMA errors. 0xffff is the max value which solves + these problems. */ + pci_write_config_dword(dev, 0x40, 0xffff); + + CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " + "irq: %d, latency: %d, memory: 0x%lx\n", + cx->dev->device, cx->card_rev, dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + cx->dev->irq, pci_latency, (unsigned long)cx->base_addr); + + return 0; +} + +static u32 cx18_request_module(struct cx18 *cx, u32 hw, + const char *name, u32 id) +{ + if ((hw & id) == 0) + return hw; + if (request_module(name) != 0) { + CX18_ERR("Failed to load module %s\n", name); + return hw & ~id; + } + CX18_DEBUG_INFO("Loaded module %s\n", name); + return hw; +} + +static void cx18_load_and_init_modules(struct cx18 *cx) +{ + u32 hw = cx->card->hw_all; + int i; + + /* load modules */ +#ifndef CONFIG_MEDIA_TUNER + hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); +#endif +#ifndef CONFIG_VIDEO_CS5345 + hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); +#endif + + /* check which i2c devices are actually found */ + for (i = 0; i < 32; i++) { + u32 device = 1 << i; + + if (!(device & hw)) + continue; + if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM || + device == CX18_HW_CX23418 || device == CX18_HW_DVB) { + /* These 'devices' do not use i2c probing */ + cx->hw_flags |= device; + continue; + } + cx18_i2c_register(cx, i); + if (cx18_i2c_hw_addr(cx, device) > 0) + cx->hw_flags |= device; + } + + hw = cx->hw_flags; +} + +static int __devinit cx18_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int retval = 0; + int vbi_buf_size; + u32 devtype; + struct cx18 *cx; + + spin_lock(&cx18_cards_lock); + + /* Make sure we've got a place for this card */ + if (cx18_cards_active == CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n", + cx18_cards_active); + spin_unlock(&cx18_cards_lock); + return -ENOMEM; + } + + cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); + if (cx == 0) { + spin_unlock(&cx18_cards_lock); + return -ENOMEM; + } + cx18_cards[cx18_cards_active] = cx; + cx->dev = dev; + cx->num = cx18_cards_active++; + snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num); + CX18_INFO("Initializing card #%d\n", cx->num); + + spin_unlock(&cx18_cards_lock); + + cx18_process_options(cx); + if (cx->options.cardtype == -1) { + retval = -ENODEV; + goto err; + } + if (cx18_init_struct1(cx)) { + retval = -ENOMEM; + goto err; + } + + CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); + + /* PCI Device Setup */ + retval = cx18_setup_pci(cx, dev, pci_id); + if (retval != 0) { + if (retval == -EIO) + goto free_workqueue; + else if (retval == -ENXIO) + goto free_mem; + } + /* save cx in the pci struct for later use */ + pci_set_drvdata(dev, cx); + + /* map io memory */ + CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); + cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, + CX18_MEM_SIZE); + if (!cx->enc_mem) { + CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); + CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); + retval = -ENOMEM; + goto free_mem; + } + cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; + devtype = read_reg(0xC72028); + switch (devtype & 0xff000000) { + case 0xff000000: + CX18_INFO("cx23418 revision %08x (A)\n", devtype); + break; + case 0x01000000: + CX18_INFO("cx23418 revision %08x (B)\n", devtype); + break; + default: + CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); + break; + } + + cx18_init_power(cx, 1); + cx18_init_memory(cx); + + cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET); + cx18_init_scb(cx); + + cx18_gpio_init(cx); + + /* active i2c */ + CX18_DEBUG_INFO("activating i2c...\n"); + if (init_cx18_i2c(cx)) { + CX18_ERR("Could not initialize i2c\n"); + goto free_map; + } + + CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active); + + if (cx->card->hw_all & CX18_HW_TVEEPROM) { + /* Based on the model number the cardtype may be changed. + The PCI IDs are not always reliable. */ + cx18_process_eeprom(cx); + } + if (cx->card->comment) + CX18_INFO("%s", cx->card->comment); + if (cx->card->v4l2_capabilities == 0) { + retval = -ENODEV; + goto free_i2c; + } + cx18_init_memory(cx); + + /* Register IRQ */ + retval = request_irq(cx->dev->irq, cx18_irq_handler, + IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx); + if (retval) { + CX18_ERR("Failed to register irq %d\n", retval); + goto free_i2c; + } + + if (cx->std == 0) + cx->std = V4L2_STD_NTSC_M; + + if (cx->options.tuner == -1) { + int i; + + for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { + if ((cx->std & cx->card->tuners[i].std) == 0) + continue; + cx->options.tuner = cx->card->tuners[i].tuner; + break; + } + } + /* if no tuner was found, then pick the first tuner in the card list */ + if (cx->options.tuner == -1 && cx->card->tuners[0].std) { + cx->std = cx->card->tuners[0].std; + cx->options.tuner = cx->card->tuners[0].tuner; + } + if (cx->options.radio == -1) + cx->options.radio = (cx->card->radio_input.audio_type != 0); + + /* The card is now fully identified, continue with card-specific + initialization. */ + cx18_init_struct2(cx); + + cx18_load_and_init_modules(cx); + + if (cx->std & V4L2_STD_525_60) { + cx->is_60hz = 1; + cx->is_out_60hz = 1; + } else { + cx->is_50hz = 1; + cx->is_out_50hz = 1; + } + cx->params.video_gop_size = cx->is_60hz ? 15 : 12; + + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000; + vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; + + if (cx->options.radio > 0) + cx->v4l2_cap |= V4L2_CAP_RADIO; + + retval = cx18_streams_setup(cx); + if (retval) { + CX18_ERR("Error %d setting up streams\n", retval); + goto free_irq; + } + retval = cx18_streams_register(cx); + if (retval) { + CX18_ERR("Error %d registering devices\n", retval); + goto free_streams; + } + + if (cx->options.tuner > -1) { + struct tuner_setup setup; + + setup.addr = ADDR_UNSET; + setup.type = cx->options.tuner; + setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + cx18_reset_tuner_gpio : NULL; + cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = cx->options.tuner, + .priv = &ctrl, + }; + cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg); + } + } + + /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) + are not. */ + cx->tuner_std = cx->std; + + cx18_init_on_first_open(cx); + + CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name); + + return 0; + +free_streams: + cx18_streams_cleanup(cx); +free_irq: + free_irq(cx->dev->irq, (void *)cx); +free_i2c: + exit_cx18_i2c(cx); +free_map: + cx18_iounmap(cx); +free_mem: + release_mem_region(cx->base_addr, CX18_MEM_SIZE); +free_workqueue: +err: + if (retval == 0) + retval = -ENODEV; + CX18_ERR("Error %d on initialization\n", retval); + + kfree(cx18_cards[cx18_cards_active]); + cx18_cards[cx18_cards_active] = NULL; + return retval; +} + +int cx18_init_on_first_open(struct cx18 *cx) +{ + int video_input; + int fw_retry_count = 3; + struct v4l2_frequency vf; + + if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) + return -ENXIO; + + if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) + return 0; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); + + /* Init the firmware twice to work around a silicon bug + * transport related. */ + + fw_retry_count = 3; + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (cx->std == V4L2_STD_NTSC_M_JP) + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + else if (cx->std & V4L2_STD_NTSC_M) + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + + video_input = cx->active_input; + cx->active_input++; /* Force update of input */ + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + cx->std++; /* Force full standard initialization */ + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std); + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf); + return 0; +} + +static void cx18_remove(struct pci_dev *pci_dev) +{ + struct cx18 *cx = pci_get_drvdata(pci_dev); + + CX18_DEBUG_INFO("Removing Card #%d\n", cx->num); + + /* Stop all captures */ + CX18_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&cx->capturing) > 0) + cx18_stop_all_captures(cx); + + /* Interrupts */ + sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + cx18_halt_firmware(cx); + + cx18_streams_cleanup(cx); + + exit_cx18_i2c(cx); + + free_irq(cx->dev->irq, (void *)cx); + + if (cx->dev) + cx18_iounmap(cx); + + release_mem_region(cx->base_addr, CX18_MEM_SIZE); + + pci_disable_device(cx->dev); + + CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); +} + +/* define a pci_driver for card detection */ +static struct pci_driver cx18_pci_driver = { + .name = "cx18", + .id_table = cx18_pci_tbl, + .probe = cx18_probe, + .remove = cx18_remove, +}; + +static int module_start(void) +{ + printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION); + + memset(cx18_cards, 0, sizeof(cx18_cards)); + + /* Validate parameters */ + if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n", + CX18_MAX_CARDS - 1); + return -1; + } + + if (cx18_debug < 0 || cx18_debug > 511) { + cx18_debug = 0; + printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); + } + + if (pci_register_driver(&cx18_pci_driver)) { + printk(KERN_ERR "cx18: Error detecting PCI card\n"); + return -ENODEV; + } + printk(KERN_INFO "cx18: End initialization\n"); + return 0; +} + +static void module_cleanup(void) +{ + int i; + + pci_unregister_driver(&cx18_pci_driver); + + for (i = 0; i < cx18_cards_active; i++) { + if (cx18_cards[i] == NULL) + continue; + kfree(cx18_cards[i]); + } +} + +module_init(module_start); +module_exit(module_cleanup); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h new file mode 100644 index 000000000000..2ee939193bb7 --- /dev/null +++ b/drivers/media/video/cx18/cx18-driver.h @@ -0,0 +1,500 @@ +/* + * cx18 driver internal defines and structures + * + * Derived from ivtv-driver.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#ifndef CX18_DRIVER_H +#define CX18_DRIVER_H + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/list.h> +#include <linux/unistd.h> +#include <linux/byteorder/swab.h> +#include <linux/pagemap.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> + +#include <linux/dvb/video.h> +#include <linux/dvb/audio.h> +#include <media/v4l2-common.h> +#include <media/tuner.h> +#include "cx18-mailbox.h" +#include "cx18-av-core.h" +#include "cx23418.h" + +/* DVB */ +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" + +#ifndef CONFIG_PCI +# error "This driver requires kernel PCI support." +#endif + +#define CX18_MEM_OFFSET 0x00000000 +#define CX18_MEM_SIZE 0x04000000 +#define CX18_REG_OFFSET 0x02000000 + +/* Maximum cx18 driver instances. */ +#define CX18_MAX_CARDS 32 + +/* Supported cards */ +#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */ +#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ +#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ +#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ +#define CX18_CARD_LAST 3 + +#define CX18_ENC_STREAM_TYPE_MPG 0 +#define CX18_ENC_STREAM_TYPE_TS 1 +#define CX18_ENC_STREAM_TYPE_YUV 2 +#define CX18_ENC_STREAM_TYPE_VBI 3 +#define CX18_ENC_STREAM_TYPE_PCM 4 +#define CX18_ENC_STREAM_TYPE_IDX 5 +#define CX18_ENC_STREAM_TYPE_RAD 6 +#define CX18_MAX_STREAMS 7 + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_CX 0x14f1 +#define PCI_DEVICE_ID_CX23418 0x5b7a + +/* subsystem vendor ID */ +#define CX18_PCI_ID_HAUPPAUGE 0x0070 +#define CX18_PCI_ID_COMPRO 0x185b +#define CX18_PCI_ID_YUAN 0x12ab + +/* ======================================================================== */ +/* ========================== START USER SETTABLE DMA VARIABLES =========== */ +/* ======================================================================== */ + +/* DMA Buffers, Default size in MB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFFERS 1 +#define CX18_DEFAULT_ENC_MPG_BUFFERS 2 +#define CX18_DEFAULT_ENC_IDX_BUFFERS 1 +#define CX18_DEFAULT_ENC_YUV_BUFFERS 2 +#define CX18_DEFAULT_ENC_VBI_BUFFERS 1 +#define CX18_DEFAULT_ENC_PCM_BUFFERS 1 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 + +/* debugging */ + +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_WARN (1 << 0) +#define CX18_DBGFLG_INFO (1 << 1) +#define CX18_DBGFLG_API (1 << 2) +#define CX18_DBGFLG_DMA (1 << 3) +#define CX18_DBGFLG_IOCTL (1 << 4) +#define CX18_DBGFLG_FILE (1 << 5) +#define CX18_DBGFLG_I2C (1 << 6) +#define CX18_DBGFLG_IRQ (1 << 7) +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_HIGHVOL (1 << 8) + +/* NOTE: extra space before comma in 'cx->num , ## args' is required for + gcc-2.95, otherwise it won't compile. */ +#define CX18_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & cx18_debug) \ + printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \ + } while (0) +#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \ + do { \ + if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ + printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \ + } while (0) +#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +/* Standard kernel messages */ +#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args) +#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args) +#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args) + +/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ +#define MPEG_FRAME_TYPE_IFRAME 1 +#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 +#define MPEG_FRAME_TYPE_ALL 7 + +#define CX18_MAX_PGM_INDEX (400) + +extern int cx18_debug; + + +struct cx18_options { + int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ +}; + +/* per-buffer bit flags */ +#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ + +/* per-stream, s_flags */ +#define CX18_F_S_CLAIMED 3 /* this stream is claimed */ +#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ +#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ +#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ +#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ + +/* per-cx18, i_flags */ +#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ +#define CX18_F_I_EOS 4 /* End of encoder stream reached */ +#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define CX18_F_I_INITED 21 /* set after first open */ +#define CX18_F_I_FAILED 22 /* set if first open failed */ + +/* These are the VBI types as they appear in the embedded VBI private packets. */ +#define CX18_SLICED_TYPE_TELETEXT_B (1) +#define CX18_SLICED_TYPE_CAPTION_525 (4) +#define CX18_SLICED_TYPE_WSS_625 (5) +#define CX18_SLICED_TYPE_VPS (7) + +struct cx18_buffer { + struct list_head list; + dma_addr_t dma_handle; + u32 id; + unsigned long b_flags; + char *buf; + + u32 bytesused; + u32 readpos; +}; + +struct cx18_queue { + struct list_head list; + u32 buffers; + u32 length; + u32 bytesused; +}; + +struct cx18_dvb { + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + int enabled; + int feeding; + + struct mutex feedlock; + +}; + +struct cx18; /* forward reference */ +struct cx18_scb; /* forward reference */ + +struct cx18_stream { + /* These first four fields are always set, even if the stream + is not actually created. */ + struct video_device *v4l2dev; /* NULL when stream not created */ + struct cx18 *cx; /* for ease of use */ + const char *name; /* name of the stream */ + int type; /* stream type */ + u32 handle; /* task handle */ + unsigned mdl_offset; + + u32 id; + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, + PCI_DMA_FROMDEVICE or + PCI_DMA_NONE */ + u64 dma_pts; + wait_queue_head_t waitq; + + /* Buffer Stats */ + u32 buffers; + u32 buf_size; + u32 buffers_stolen; + + /* Buffer Queues */ + struct cx18_queue q_free; /* free buffers */ + struct cx18_queue q_full; /* full buffers */ + struct cx18_queue q_io; /* waiting for I/O */ + + /* DVB / Digital Transport */ + struct cx18_dvb dvb; +}; + +struct cx18_open_id { + u32 open_id; + int type; + enum v4l2_priority prio; + struct cx18 *cx; +}; + +/* forward declaration of struct defined in cx18-cards.h */ +struct cx18_card; + + +#define CX18_VBI_FRAMES 32 + +/* VBI data */ +struct vbi_info { + u32 enc_size; + u32 frame; + u8 cc_data_odd[256]; + u8 cc_data_even[256]; + int cc_pos; + u8 cc_no_update; + u8 vps[5]; + u8 vps_found; + int wss; + u8 wss_found; + u8 wss_no_update; + u32 raw_decoder_line_size; + u8 raw_decoder_sav_odd_field; + u8 raw_decoder_sav_even_field; + u32 sliced_decoder_line_size; + u8 sliced_decoder_sav_odd_field; + u8 sliced_decoder_sav_even_field; + struct v4l2_format in; + /* convenience pointer to sliced struct in vbi_in union */ + struct v4l2_sliced_vbi_format *sliced_in; + u32 service_set_in; + int insert_mpeg; + + /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. + One for /dev/vbi0 and one for /dev/vbi8 */ + struct v4l2_sliced_vbi_data sliced_data[36]; + + /* Buffer for VBI data inserted into MPEG stream. + The first byte is a dummy byte that's never used. + The next 16 bytes contain the MPEG header for the VBI data, + the remainder is the actual VBI data. + The max size accepted by the MPEG VBI reinsertion turns out + to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, + where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is + a single line header byte and 2 * 18 is the number of VBI lines per frame. + + However, it seems that the data must be 1K aligned, so we have to + pad the data until the 1 or 2 K boundary. + + This pointer array will allocate 2049 bytes to store each VBI frame. */ + u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; + u32 sliced_mpeg_size[CX18_VBI_FRAMES]; + struct cx18_buffer sliced_mpeg_buf; + u32 inserted_frame; + + u32 start[2], count; + u32 raw_size; + u32 sliced_size; +}; + +/* Per cx23418, per I2C bus private algo callback data */ +struct cx18_i2c_algo_callback_data { + struct cx18 *cx; + int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ +}; + +/* Struct to hold info about cx18 cards */ +struct cx18 { + int num; /* board number, -1 during init! */ + char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */ + struct pci_dev *dev; /* PCI device */ + const struct cx18_card *card; /* card information */ + const char *card_name; /* full name of the card */ + const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ + u8 is_50hz; + u8 is_60hz; + u8 is_out_50hz; + u8 is_out_60hz; + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u16 buffer_id; /* buffer ID counter */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* Hardware description of the board */ + unsigned mdl_offset; + struct cx18_scb *scb; /* pointer to SCB */ + + struct cx18_av_state av_state; + + /* codec settings */ + struct cx2341x_mpeg_params params; + u32 filter_mode; + u32 temporal_strength; + u32 spatial_strength; + + /* dualwatch */ + unsigned long dualwatch_jiffies; + u16 dualwatch_stereo_mode; + + /* Digitizer type */ + int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ + + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct cx18_options options; /* User options */ + int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ + struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ + unsigned long i_flags; /* global cx18 flags */ + atomic_t capturing; /* count number of active capture streams */ + spinlock_t lock; /* lock access to this struct */ + int search_pack_header; + + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + + int open_id; /* incremented each time an open occurs, used as + unique ID. Starts at 1, so 0 can be used as + uninitialized value in the stream->id. */ + + u32 base_addr; + struct v4l2_prio_state prio; + + u8 card_rev; + void __iomem *enc_mem, *reg_mem; + + struct vbi_info vbi; + + u32 pgm_info_offset; + u32 pgm_info_num; + u32 pgm_info_write_idx; + u32 pgm_info_read_idx; + struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX]; + + u64 mpg_data_received; + u64 vbi_data_inserted; + + wait_queue_head_t mb_apu_waitq; + wait_queue_head_t mb_cpu_waitq; + wait_queue_head_t mb_epu_waitq; + wait_queue_head_t mb_hpu_waitq; + wait_queue_head_t cap_w; + /* when the current DMA is finished this queue is woken up */ + wait_queue_head_t dma_waitq; + + /* i2c */ + struct i2c_adapter i2c_adap[2]; + struct i2c_algo_bit_data i2c_algo[2]; + struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; + struct i2c_client i2c_client[2]; + struct mutex i2c_bus_lock[2]; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + + /* v4l2 and User settings */ + + /* codec settings */ + u32 audio_input; + u32 active_input; + u32 active_output; + v4l2_std_id std; + v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ +}; + +/* Globals */ +extern struct cx18 *cx18_cards[]; +extern int cx18_cards_active; +extern int cx18_first_minor; +extern spinlock_t cx18_cards_lock; + +/*==============Prototypes==================*/ + +/* Return non-zero if a signal is pending */ +int cx18_msleep_timeout(unsigned int msecs, int intr); + +/* Wait on queue, returns -EINTR if interrupted */ +int cx18_waitq(wait_queue_head_t *waitq); + +/* Read Hauppauge eeprom */ +struct tveeprom; /* forward reference */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); + +/* First-open initialization: load firmware, etc. */ +int cx18_init_on_first_open(struct cx18 *cx); + +/* This is a PCI post thing, where if the pci register is not read, then + the write doesn't always take effect right away. By reading back the + register any pending PCI writes will be performed (in order), and so + you can be sure that the writes are guaranteed to be done. + + Rarely needed, only in some timing sensitive cases. + Apparently if this is not done some motherboards seem + to kill the firmware and get into the broken state until computer is + rebooted. */ +#define write_sync(val, reg) \ + do { writel(val, reg); readl(reg); } while (0) + +#define read_reg(reg) readl(cx->reg_mem + (reg)) +#define write_reg(val, reg) writel(val, cx->reg_mem + (reg)) +#define write_reg_sync(val, reg) \ + do { write_reg(val, reg); read_reg(reg); } while (0) + +#define read_enc(addr) readl(cx->enc_mem + (u32)(addr)) +#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr)) +#define write_enc_sync(val, addr) \ + do { write_enc(val, addr); read_enc(addr); } while (0) + +#define sw1_irq_enable(val) do { \ + write_reg(val, SW1_INT_STATUS); \ + write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \ +} while (0) + +#define sw1_irq_disable(val) \ + write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI); + +#define sw2_irq_enable(val) do { \ + write_reg(val, SW2_INT_STATUS); \ + write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \ +} while (0) + +#define sw2_irq_disable(val) \ + write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI); + +#define setup_page(addr) do { \ + u32 val = read_reg(0xD000F8) & ~0x1f00; \ + write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \ +} while (0) + +#endif /* CX18_DRIVER_H */ diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c new file mode 100644 index 000000000000..65efe69d939a --- /dev/null +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -0,0 +1,288 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-version.h" +#include "cx18-dvb.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "s5h1409.h" + +/* Wait until the MXL500X driver is merged */ +#ifdef HAVE_MXL500X +#include "mxl500x.h" +#endif + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 + +#ifdef HAVE_MXL500X +static struct mxl500x_config hauppauge_hvr1600_tuner = { + .delsys = MXL500x_MODE_ATSC, + .octf = MXL500x_OCTF_CH, + .xtal_freq = 16000000, + .iflo_freq = 5380000, + .ref_freq = 322800000, + .rssi_ena = MXL_RSSI_ENABLE, + .addr = 0xC6 >> 1, +}; + +static struct s5h1409_config hauppauge_hvr1600_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK + +}; +#endif + +static int dvb_register(struct cx18_stream *stream); + +/* Kernel DVB framework calls this when the feed needs to start. + * The CX18 framework should enable the transport DMA handling + * and queue processing. + */ +static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *) demux->priv; + struct cx18 *cx = stream->cx; + int ret = -EINVAL; + u32 v; + + CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + switch (cx->card->type) { + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL); + v |= 0x00400000; /* Serial Mode */ + v |= 0x00002000; /* Data Length - Byte */ + v |= 0x00010000; /* Error - Polarity */ + v |= 0x00020000; /* Error - Passthru */ + v |= 0x000c0000; /* Error - Ignore */ + write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); + break; + + default: + /* Assumption - Parallel transport - Signalling + * undefined or default. + */ + break; + } + + if (!demux->dmx.frontend) + return -EINVAL; + + if (stream) { + mutex_lock(&stream->dvb.feedlock); + if (stream->dvb.feeding++ == 0) { + CX18_DEBUG_INFO("Starting Transport DMA\n"); + ret = cx18_start_v4l2_encode_stream(stream); + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); + } + + return ret; +} + +/* Kernel DVB framework calls this when the feed needs to stop. */ +static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *)demux->priv; + struct cx18 *cx = stream->cx; + int ret = -EINVAL; + + CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + + if (stream) { + mutex_lock(&stream->dvb.feedlock); + if (--stream->dvb.feeding == 0) { + CX18_DEBUG_INFO("Stopping Transport DMA\n"); + ret = cx18_stop_v4l2_encode_stream(stream, 0); + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); + } + + return ret; +} + +int cx18_dvb_register(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = &stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret; + + if (!dvb) + return -EINVAL; + + ret = dvb_register_adapter(&dvb->dvb_adapter, + CX18_DRIVER_NAME, + THIS_MODULE, &cx->dev->dev, adapter_nr); + if (ret < 0) + goto err_out; + + dvb_adapter = &dvb->dvb_adapter; + + dvbdemux = &dvb->demux; + + dvbdemux->priv = (void *)stream; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = cx18_dvb_start_feed; + dvbdemux->stop_feed = cx18_dvb_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + dvb->hw_frontend.source = DMX_FRONTEND_0; + dvb->mem_frontend.source = DMX_MEMORY_FE; + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &dvb->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = dvb_register(stream); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); + + CX18_INFO("DVB Frontend registered\n"); + mutex_init(&dvb->feedlock); + dvb->enabled = 1; + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dvb->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dvb->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dvb->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_out: + return ret; +} + +void cx18_dvb_unregister(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = &stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + + CX18_INFO("unregister DVB\n"); + + dvb_adapter = &dvb->dvb_adapter; + dvbdemux = &dvb->demux; + dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&dvb->dvbnet); + dmx->remove_frontend(dmx, &dvb->mem_frontend); + dmx->remove_frontend(dmx, &dvb->hw_frontend); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_frontend(dvb->fe); + dvb_frontend_detach(dvb->fe); + dvb_unregister_adapter(dvb_adapter); +} + +/* All the DVB attach calls go here, this function get's modified + * for each new card. No other function in this file needs + * to change. + */ +static int dvb_register(struct cx18_stream *stream) +{ + struct cx18_dvb *dvb = &stream->dvb; + struct cx18 *cx = stream->cx; + int ret = 0; + + switch (cx->card->type) { +/* Wait until the MXL500X driver is merged */ +#ifdef HAVE_MXL500X + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + dvb->fe = dvb_attach(s5h1409_attach, + &hauppauge_hvr1600_config, + &cx->i2c_adap[0]); + if (dvb->fe != NULL) { + dvb_attach(mxl500x_attach, dvb->fe, + &hauppauge_hvr1600_tuner, + &cx->i2c_adap[0]); + ret = 0; + } + break; +#endif + default: + /* No Digital Tv Support */ + break; + } + + if (dvb->fe == NULL) { + CX18_ERR("frontend initialization failed\n"); + return -1; + } + + ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); + if (ret < 0) { + if (dvb->fe->ops.release) + dvb->fe->ops.release(dvb->fe); + return ret; + } + + return ret; +} diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h new file mode 100644 index 000000000000..d6a6ccda79a9 --- /dev/null +++ b/drivers/media/video/cx18/cx18-dvb.h @@ -0,0 +1,25 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-driver.h" + +int cx18_dvb_register(struct cx18_stream *stream); +void cx18_dvb_unregister(struct cx18_stream *stream); diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c new file mode 100644 index 000000000000..69303065a294 --- /dev/null +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -0,0 +1,711 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-mailbox.h" +#include "cx18-scb.h" +#include "cx18-streams.h" +#include "cx18-controls.h" +#include "cx18-ioctl.h" +#include "cx18-cards.h" + +/* This function tries to claim the stream for a specific file descriptor. + If no one else is using this stream then the stream is claimed and + associated VBI streams are also automatically claimed. + Possible error returns: -EBUSY if someone else has claimed + the stream or 0 on success. */ +int cx18_claim_stream(struct cx18_open_id *id, int type) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[type]; + struct cx18_stream *s_vbi; + int vbi_type; + + if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + /* someone already claimed this stream */ + if (s->id == id->open_id) { + /* yes, this file descriptor did. So that's OK. */ + return 0; + } + if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { + /* VBI is handled already internally, now also assign + the file descriptor to this stream for external + reading of the stream. */ + s->id = id->open_id; + CX18_DEBUG_INFO("Start Read VBI\n"); + return 0; + } + /* someone else is using this stream already */ + CX18_DEBUG_INFO("Stream %d is busy\n", type); + return -EBUSY; + } + s->id = id->open_id; + + /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI, + CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI + (provided VBI insertion is on and sliced VBI is selected), for all + other streams we're done */ + if (type == CX18_ENC_STREAM_TYPE_MPG && + cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) { + vbi_type = CX18_ENC_STREAM_TYPE_VBI; + } else { + return 0; + } + s_vbi = &cx->streams[vbi_type]; + + set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); + + /* mark that it is used internally */ + set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags); + return 0; +} + +/* This function releases a previously claimed stream. It will take into + account associated VBI streams. */ +void cx18_release_stream(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi; + + s->id = -1; + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { + /* this stream is still in use internally */ + return; + } + if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); + return; + } + + cx18_flush_queues(s); + + /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI, + for all other streams we're done */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + else + return; + + /* clear internal use flag */ + if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) { + /* was already cleared */ + return; + } + if (s_vbi->id != -1) { + /* VBI stream still claimed by a file descriptor */ + return; + } + clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); + cx18_flush_queues(s_vbi); +} + +static void cx18_dualwatch(struct cx18 *cx) +{ + struct v4l2_tuner vt; + u16 new_bitmap; + u16 new_stereo_mode; + const u16 stereo_mask = 0x0300; + const u16 dual = 0x0200; + + new_stereo_mode = cx->params.audio_properties & stereo_mask; + memset(&vt, 0, sizeof(vt)); + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt); + if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && + (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) + new_stereo_mode = dual; + + if (new_stereo_mode == cx->dualwatch_stereo_mode) + return; + + new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask); + + CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n", + cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); + + if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + cx18_find_handle(cx), new_bitmap) == 0) { + cx->dualwatch_stereo_mode = new_stereo_mode; + return; + } + CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); +} + + +static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + struct cx18_buffer *buf; + DEFINE_WAIT(wait); + + *err = 0; + while (1) { + if (s->type == CX18_ENC_STREAM_TYPE_MPG) { + + if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { + cx->dualwatch_jiffies = jiffies; + cx18_dualwatch(cx); + } + if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { + /* byteswap and process VBI data */ +/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */ + cx18_enqueue(s_vbi, buf, &s_vbi->q_free); + } + } + buf = &cx->vbi.sliced_mpeg_buf; + if (buf->readpos != buf->bytesused) + return buf; + } + + /* do we have leftover data? */ + buf = cx18_dequeue(s, &s->q_io); + if (buf) + return buf; + + /* do we have new data? */ + buf = cx18_dequeue(s, &s->q_full); + if (buf) { + if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP, + &buf->b_flags)) + return buf; + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + /* byteswap MPG data */ + cx18_buf_swap(buf); + else { + /* byteswap and process VBI data */ + cx18_process_vbi_data(cx, buf, + s->dma_pts, s->type); + } + return buf; + } + + /* return if end of stream */ + if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + CX18_DEBUG_INFO("EOS %s\n", s->name); + return NULL; + } + + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + + /* wait for more data to arrive */ + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); + /* New buffers might have become available before we were added + to the waitqueue */ + if (!s->q_full.buffers) + schedule(); + finish_wait(&s->waitq, &wait); + if (signal_pending(current)) { + /* return if a signal was received */ + CX18_DEBUG_INFO("User stopped %s\n", s->name); + *err = -EINTR; + return NULL; + } + } +} + +static void cx18_setup_sliced_vbi_buf(struct cx18 *cx) +{ + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx]; + cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx]; + cx->vbi.sliced_mpeg_buf.readpos = 0; +} + +static size_t cx18_copy_buf_to_user(struct cx18_stream *s, + struct cx18_buffer *buf, char __user *ubuf, size_t ucount) +{ + struct cx18 *cx = s->cx; + size_t len = buf->bytesused - buf->readpos; + + if (len > ucount) + len = ucount; + if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && + cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) { + const char *start = buf->buf + buf->readpos; + const char *p = start + 1; + const u8 *q; + u8 ch = cx->search_pack_header ? 0xba : 0xe0; + int stuffing, i; + + while (start + len > p) { + q = memchr(p, 0, start + len - p); + if (q == NULL) + break; + p = q + 1; + if ((char *)q + 15 >= buf->buf + buf->bytesused || + q[1] != 0 || q[2] != 1 || q[3] != ch) + continue; + if (!cx->search_pack_header) { + if ((q[6] & 0xc0) != 0x80) + continue; + if (((q[7] & 0xc0) == 0x80 && + (q[9] & 0xf0) == 0x20) || + ((q[7] & 0xc0) == 0xc0 && + (q[9] & 0xf0) == 0x30)) { + ch = 0xba; + cx->search_pack_header = 1; + p = q + 9; + } + continue; + } + stuffing = q[13] & 7; + /* all stuffing bytes must be 0xff */ + for (i = 0; i < stuffing; i++) + if (q[14 + i] != 0xff) + break; + if (i == stuffing && + (q[4] & 0xc4) == 0x44 && + (q[12] & 3) == 3 && + q[14 + stuffing] == 0 && + q[15 + stuffing] == 0 && + q[16 + stuffing] == 1) { + cx->search_pack_header = 0; + len = (char *)q - start; + cx18_setup_sliced_vbi_buf(cx); + break; + } + } + } + if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { + CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", + len, s->name); + return -EFAULT; + } + buf->readpos += len; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + buf != &cx->vbi.sliced_mpeg_buf) + cx->mpg_data_received += len; + return len; +} + +static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, + size_t tot_count, int non_block) +{ + struct cx18 *cx = s->cx; + size_t tot_written = 0; + int single_frame = 0; + + if (atomic_read(&cx->capturing) == 0 && s->id == -1) { + /* shouldn't happen */ + CX18_DEBUG_WARN("Stream %s not initialized before read\n", + s->name); + return -EIO; + } + + /* Each VBI buffer is one frame, the v4l2 API says that for VBI the + frames should arrive one-by-one, so make sure we never output more + than one VBI frame at a time */ + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set) + single_frame = 1; + + for (;;) { + struct cx18_buffer *buf; + int rc; + + buf = cx18_get_buffer(s, non_block, &rc); + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + cx18_release_stream(s); + } + /* set errno */ + return rc; + } + + rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written, + tot_count - tot_written); + + if (buf != &cx->vbi.sliced_mpeg_buf) { + if (buf->readpos == buf->bytesused) { + cx18_buf_sync_for_device(s, buf); + cx18_enqueue(s, buf, &s->q_free); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, + s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } else + cx18_enqueue(s, buf, &s->q_io); + } else if (buf->readpos == buf->bytesused) { + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_size[idx] = 0; + cx->vbi.inserted_frame++; + cx->vbi_data_inserted += buf->bytesused; + } + if (rc < 0) + return rc; + tot_written += rc; + + if (tot_written == tot_count || single_frame) + break; + } + return tot_written; +} + +static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, + size_t count, loff_t *pos, int non_block) +{ + ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; + struct cx18 *cx = s->cx; + + CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); + if (rc > 0) + pos += rc; + return rc; +} + +int cx18_start_capture(struct cx18_open_id *id) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct cx18_stream *s_vbi; + + if (s->type == CX18_ENC_STREAM_TYPE_RAD) { + /* you cannot read from these stream types. */ + return -EPERM; + } + + /* Try to claim this stream. */ + if (cx18_claim_stream(id, s->type)) + return -EBUSY; + + /* If capture is already in progress, then we also have to + do nothing extra. */ + if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || + test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + return 0; + } + + /* Start VBI capture if required */ + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed + automatically when the MPG stream is claimed. + We only need to start the VBI capturing. */ + if (cx18_start_v4l2_encode_stream(s_vbi)) { + CX18_DEBUG_WARN("VBI capture start failed\n"); + + /* Failure, clean up and return an error */ + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* also releases the associated VBI stream */ + cx18_release_stream(s); + return -EIO; + } + CX18_DEBUG_INFO("VBI insertion started\n"); + } + + /* Tell the card to start capturing */ + if (!cx18_start_v4l2_encode_stream(s)) { + /* We're done */ + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + /* Resume a possibly paused encoder */ + if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); + return 0; + } + + /* failure, clean up */ + CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); + + /* Note: the CX18_ENC_STREAM_TYPE_VBI is released + automatically when the MPG stream is released. + We only need to stop the VBI capturing. */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + cx18_stop_v4l2_encode_stream(s_vbi, 0); + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + } + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + cx18_release_stream(s); + return -EIO; +} + +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int rc; + + CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) + return rc; + return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); +} + +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + /* Start a capture if there is none */ + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + int rc; + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) { + CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", + s->name, rc); + return POLLERR; + } + CX18_DEBUG_FILE("Encoder poll started capture\n"); + } + + /* add stream's waitq to the poll list */ + CX18_DEBUG_HI_FILE("Encoder poll\n"); + poll_wait(filp, &s->waitq, wait); + + if (s->q_full.length || s->q_io.length) + return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; + return 0; +} + +void cx18_stop_capture(struct cx18_open_id *id, int gop_end) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + /* 'Unclaim' this stream */ + + /* Stop capturing */ + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + struct cx18_stream *s_vbi = + &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + + CX18_DEBUG_INFO("close stopping capture\n"); + /* Special case: a running VBI capture for VBI insertion + in the mpeg stream. Need to stop that too. */ + if (id->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + CX18_DEBUG_INFO("close stopping embedded VBI capture\n"); + cx18_stop_v4l2_encode_stream(s_vbi, 0); + } + if (id->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) + /* Also used internally, don't stop capturing */ + s->id = -1; + else + cx18_stop_v4l2_encode_stream(s, gop_end); + } + if (!gop_end) { + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + cx18_release_stream(s); + } +} + +int cx18_v4l2_close(struct inode *inode, struct file *filp) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + v4l2_prio_close(&cx->prio, &id->prio); + + /* Easy case first: this stream was never claimed by us */ + if (s->id != id->open_id) { + kfree(id); + return 0; + } + + /* 'Unclaim' this stream */ + + /* Stop radio */ + mutex_lock(&cx->serialize_lock); + if (id->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Closing radio device, return to TV mode */ + cx18_mute(cx); + /* Mark that the radio is no longer in use */ + clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* Switch tuner to TV */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + /* Select correct audio input (i.e. TV tuner or Line in) */ + cx18_audio_set_io(cx); + if (atomic_read(&cx->capturing) > 0) { + /* Undo video mute */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, + cx->params.video_mute | + (cx->params.video_mute_yuv << 8)); + } + /* Done! Unmute and continue. */ + cx18_unmute(cx); + cx18_release_stream(s); + } else { + cx18_stop_capture(id, 0); + } + kfree(id); + mutex_unlock(&cx->serialize_lock); + return 0; +} + +static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) +{ + struct cx18 *cx = s->cx; + struct cx18_open_id *item; + + CX18_DEBUG_FILE("open %s\n", s->name); + + /* Allocate memory */ + item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL); + if (NULL == item) { + CX18_DEBUG_WARN("nomem on v4l2 open\n"); + return -ENOMEM; + } + item->cx = cx; + item->type = s->type; + v4l2_prio_open(&cx->prio, &item->prio); + + item->open_id = cx->open_id++; + filp->private_data = item; + + if (item->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Try to claim this stream */ + if (cx18_claim_stream(item, item->type)) { + /* No, it's already in use */ + kfree(item); + return -EBUSY; + } + + if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + if (atomic_read(&cx->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + cx18_release_stream(s); + kfree(item); + return -EBUSY; + } + } + + /* Mark that the radio is being used. */ + set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* We have the radio */ + cx18_mute(cx); + /* Switch tuner to radio */ + cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL); + /* Select the correct audio input (i.e. radio tuner) */ + cx18_audio_set_io(cx); + /* Done! Unmute and continue. */ + cx18_unmute(cx); + } + return 0; +} + +int cx18_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct cx18 *cx = NULL; + struct cx18_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&cx18_cards_lock); + for (x = 0; cx == NULL && x < cx18_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < CX18_MAX_STREAMS; y++) { + s = &cx18_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + cx = cx18_cards[x]; + break; + } + } + } + spin_unlock(&cx18_cards_lock); + + if (cx == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + printk(KERN_WARNING "No cx18 device found on minor %d\n", + minor); + return -ENXIO; + } + + mutex_lock(&cx->serialize_lock); + if (cx18_init_on_first_open(cx)) { + CX18_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&cx->serialize_lock); + return -ENXIO; + } + res = cx18_serialized_open(s, filp); + mutex_unlock(&cx->serialize_lock); + return res; +} + +void cx18_mute(struct cx18 *cx) +{ + if (atomic_read(&cx->capturing)) + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + cx18_find_handle(cx), 1); + CX18_DEBUG_INFO("Mute\n"); +} + +void cx18_unmute(struct cx18 *cx) +{ + if (atomic_read(&cx->capturing)) { + cx18_msleep_timeout(100, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, + cx18_find_handle(cx), 12); + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + cx18_find_handle(cx), 0); + } + CX18_DEBUG_INFO("Unmute\n"); +} diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h new file mode 100644 index 000000000000..16cdafbd24c5 --- /dev/null +++ b/drivers/media/video/cx18/cx18-fileops.h @@ -0,0 +1,45 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +/* Testing/Debugging */ +int cx18_v4l2_open(struct inode *inode, struct file *filp); +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos); +ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, + loff_t *pos); +int cx18_v4l2_close(struct inode *inode, struct file *filp); +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); +int cx18_start_capture(struct cx18_open_id *id); +void cx18_stop_capture(struct cx18_open_id *id, int gop_end); +void cx18_mute(struct cx18 *cx); +void cx18_unmute(struct cx18 *cx); + +/* Utilities */ + +/* Try to claim a stream for the filehandle. Return 0 on success, + -EBUSY if stream already claimed. Once a stream is claimed, it + remains claimed until the associated filehandle is closed. */ +int cx18_claim_stream(struct cx18_open_id *id, int type); + +/* Release a previously claimed stream. */ +void cx18_release_stream(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c new file mode 100644 index 000000000000..2694ce350631 --- /dev/null +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -0,0 +1,373 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-firmware.h" +#include "cx18-cards.h" +#include <linux/firmware.h> + +#define CX18_PROC_SOFT_RESET 0xc70010 +#define CX18_DDR_SOFT_RESET 0xc70014 +#define CX18_CLOCK_SELECT1 0xc71000 +#define CX18_CLOCK_SELECT2 0xc71004 +#define CX18_HALF_CLOCK_SELECT1 0xc71008 +#define CX18_HALF_CLOCK_SELECT2 0xc7100C +#define CX18_CLOCK_POLARITY1 0xc71010 +#define CX18_CLOCK_POLARITY2 0xc71014 +#define CX18_ADD_DELAY_ENABLE1 0xc71018 +#define CX18_ADD_DELAY_ENABLE2 0xc7101C +#define CX18_CLOCK_ENABLE1 0xc71020 +#define CX18_CLOCK_ENABLE2 0xc71024 + +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_FAST_CLOCK_PLL_INT 0xc78000 +#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 +#define CX18_FAST_CLOCK_PLL_POST 0xc78008 +#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C +#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 + +#define CX18_SLOW_CLOCK_PLL_INT 0xc78014 +#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 +#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C +#define CX18_MPEG_CLOCK_PLL_INT 0xc78040 +#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 +#define CX18_MPEG_CLOCK_PLL_POST 0xc78048 +#define CX18_PLL_POWER_DOWN 0xc78088 +#define CX18_SW1_INT_STATUS 0xc73104 +#define CX18_SW1_INT_ENABLE_PCI 0xc7311C +#define CX18_SW2_INT_SET 0xc73140 +#define CX18_SW2_INT_STATUS 0xc73144 +#define CX18_ADEC_CONTROL 0xc78120 + +#define CX18_DDR_REQUEST_ENABLE 0xc80000 +#define CX18_DDR_CHIP_CONFIG 0xc80004 +#define CX18_DDR_REFRESH 0xc80008 +#define CX18_DDR_TIMING1 0xc8000C +#define CX18_DDR_TIMING2 0xc80010 +#define CX18_DDR_POWER_REG 0xc8001C + +#define CX18_DDR_TUNE_LANE 0xc80048 +#define CX18_DDR_INITIAL_EMRS 0xc80054 +#define CX18_DDR_MB_PER_ROW_7 0xc8009C +#define CX18_DDR_BASE_63_ADDR 0xc804FC + +#define CX18_WMB_CLIENT02 0xc90108 +#define CX18_WMB_CLIENT05 0xc90114 +#define CX18_WMB_CLIENT06 0xc90118 +#define CX18_WMB_CLIENT07 0xc9011C +#define CX18_WMB_CLIENT08 0xc90120 +#define CX18_WMB_CLIENT09 0xc90124 +#define CX18_WMB_CLIENT10 0xc90128 +#define CX18_WMB_CLIENT11 0xc9012C +#define CX18_WMB_CLIENT12 0xc90130 +#define CX18_WMB_CLIENT13 0xc90134 +#define CX18_WMB_CLIENT14 0xc90138 + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +/* Encoder/decoder firmware sizes */ +#define CX18_FW_CPU_SIZE (174716) +#define CX18_FW_APU_SIZE (141200) + +#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ +#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ + +struct cx18_apu_rom_seghdr { + u32 sync1; + u32 sync2; + u32 addr; + u32 size; +}; + +static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + int i, j; + u32 __iomem *dst = (u32 __iomem *)mem; + const u32 *src; + +retry: + if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n", + fn, size); + CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with + udev <0.95) the wrong file was sometimes loaded. So we check + filesizes to see if at least the right-sized file was + loaded. If not, then we retry. */ + CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", + fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + for (i = 0; i < fw->size; i += 4096) { + setup_page(i); + for (j = i; j < fw->size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(*src, dst); + if (__raw_readl(dst) != *src) { + CX18_ERR("Mismatch at offset %x\n", i); + release_firmware(fw); + return -EIO; + } + dst++; + src++; + } + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + release_firmware(fw); + return size; +} + +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + int i, j; + const u32 *src; + struct cx18_apu_rom_seghdr seghdr; + const u8 *vers; + u32 offset = 0; + u32 apu_version = 0; + int sz; + +retry: + if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("unable to open firmware %s (must be %ld bytes)\n", + fn, size); + CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + vers = fw->data + sizeof(seghdr); + sz = fw->size; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with + udev <0.95) the wrong file was sometimes loaded. So we check + filesizes to see if at least the right-sized file was + loaded. If not, then we retry. */ + CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", + fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; + while (offset + sizeof(seghdr) < size) { + /* TODO: byteswapping */ + memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); + offset += sizeof(seghdr); + if (seghdr.sync1 != APU_ROM_SYNC1 || + seghdr.sync2 != APU_ROM_SYNC2) { + offset += seghdr.size; + continue; + } + CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, + seghdr.addr + seghdr.size - 1); + if (offset + seghdr.size > sz) + break; + for (i = 0; i < seghdr.size; i += 4096) { + setup_page(offset + i); + for (j = i; j < seghdr.size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j); + if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) { + CX18_ERR("Mismatch at offset %x\n", offset + j); + release_firmware(fw); + return -EIO; + } + } + } + offset += seghdr.size; + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + fn, apu_version, fw->size); + release_firmware(fw); + /* Clear bit0 for APU to start from 0 */ + write_reg(read_reg(0xc72030) & ~1, 0xc72030); + return size; +} + +void cx18_halt_firmware(struct cx18 *cx) +{ + CX18_DEBUG_INFO("Preparing for firmware halt.\n"); + write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + write_reg(0x00020002, CX18_ADEC_CONTROL); +} + +void cx18_init_power(struct cx18 *cx, int lowpwr) +{ + /* power-down Spare and AOM PLLs */ + /* power-up fast, slow and mpeg PLLs */ + write_reg(0x00000008, CX18_PLL_POWER_DOWN); + + /* ADEC out of sleep */ + write_reg(0x00020000, CX18_ADEC_CONTROL); + + /* The fast clock is at 200/245 MHz */ + write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); + write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC); + + write_reg(2, CX18_FAST_CLOCK_PLL_POST); + write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE); + write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); + + /* set slow clock to 125/120 MHz */ + write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT); + write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC); + write_reg(4, CX18_SLOW_CLOCK_PLL_POST); + + /* mpeg clock pll 54MHz */ + write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT); + write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC); + write_reg(8, CX18_MPEG_CLOCK_PLL_POST); + + /* Defaults */ + /* APU = SC or SC/2 = 125/62.5 */ + /* EPU = SC = 125 */ + /* DDR = FC = 180 */ + /* ENC = SC = 125 */ + /* AI1 = SC = 125 */ + /* VIM2 = disabled */ + /* PCI = FC/2 = 90 */ + /* AI2 = disabled */ + /* DEMUX = disabled */ + /* AO = SC/2 = 62.5 */ + /* SER = 54MHz */ + /* VFC = disabled */ + /* USB = disabled */ + + write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1); + write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2); + + write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1); + write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2); + + write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1); + write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2); +} + +void cx18_init_memory(struct cx18 *cx) +{ + cx18_msleep_timeout(10, 0); + write_reg(0x10000, CX18_DDR_SOFT_RESET); + cx18_msleep_timeout(10, 0); + + write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); + + cx18_msleep_timeout(10, 0); + + write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH); + write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1); + write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2); + + cx18_msleep_timeout(10, 0); + + /* Initialize DQS pad time */ + write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); + write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); + + cx18_msleep_timeout(10, 0); + + write_reg(0x20000, CX18_DDR_SOFT_RESET); + cx18_msleep_timeout(10, 0); + + /* use power-down mode when idle */ + write_reg(0x00000010, CX18_DDR_POWER_REG); + + write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN); + + write_reg(0x48, CX18_DDR_MB_PER_ROW_7); + write_reg(0xE0000, CX18_DDR_BASE_63_ADDR); + + write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */ + write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */ + write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ + write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */ + write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ + write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */ + write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */ + write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */ + write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */ + write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */ +} + +int cx18_firmware_init(struct cx18 *cx) +{ + /* Allow chip to control CLKRUN */ + write_reg(0x5, CX18_DSP0_INTERRUPT_MASK); + + write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + + cx18_msleep_timeout(1, 0); + + sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + /* Only if the processor is not running */ + if (read_reg(CX18_PROC_SOFT_RESET) & 8) { + int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", + cx->enc_mem, cx, CX18_FW_APU_SIZE); + + sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", + cx->enc_mem, cx, CX18_FW_CPU_SIZE); + + if (sz > 0) { + int retries = 0; + + /* start the CPU */ + write_reg(0x00080000, CX18_PROC_SOFT_RESET); + while (retries++ < 50) { /* Loop for max 500mS */ + if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0) + break; + cx18_msleep_timeout(10, 0); + } + cx18_msleep_timeout(200, 0); + if (retries == 51) { + CX18_ERR("Could not start the CPU\n"); + return -EIO; + } + } + if (sz <= 0) + return -EIO; + } + /* initialize GPIO */ + write_reg(0x14001400, 0xC78110); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h new file mode 100644 index 000000000000..38d4c05e8499 --- /dev/null +++ b/drivers/media/video/cx18/cx18-firmware.h @@ -0,0 +1,25 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +int cx18_firmware_init(struct cx18 *cx); +void cx18_halt_firmware(struct cx18 *cx); +void cx18_init_memory(struct cx18 *cx); +void cx18_init_power(struct cx18 *cx, int lowpwr); diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c new file mode 100644 index 000000000000..19253e6b8673 --- /dev/null +++ b/drivers/media/video/cx18/cx18-gpio.c @@ -0,0 +1,74 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "tuner-xc2028.h" + +/********************* GPIO stuffs *********************/ + +/* GPIO registers */ +#define CX18_REG_GPIO_IN 0xc72010 +#define CX18_REG_GPIO_OUT1 0xc78100 +#define CX18_REG_GPIO_DIR1 0xc78108 +#define CX18_REG_GPIO_OUT2 0xc78104 +#define CX18_REG_GPIO_DIR2 0xc7810c + +/* + * HVR-1600 GPIO pins, courtesy of Hauppauge: + * + * gpio0: zilog ir process reset pin + * gpio1: zilog programming pin (you should never use this) + * gpio12: cx24227 reset pin + * gpio13: cs5345 reset pin +*/ + +void cx18_gpio_init(struct cx18 *cx) +{ + if (cx->card->gpio_init.direction == 0) + return; + + CX18_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", + read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_OUT1)); + + /* init output data then direction */ + write_reg(cx->card->gpio_init.direction << 16, CX18_REG_GPIO_DIR1); + write_reg(0, CX18_REG_GPIO_DIR2); + write_reg((cx->card->gpio_init.direction << 16) | + cx->card->gpio_init.initial_value, CX18_REG_GPIO_OUT1); + write_reg(0, CX18_REG_GPIO_OUT2); +} + +/* Xceive tuner reset function */ +int cx18_reset_tuner_gpio(void *dev, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct cx18 *cx = algo->data; +/* int curdir, curout;*/ + + if (cmd != XC2028_TUNER_RESET) + return 0; + CX18_DEBUG_INFO("Resetting tuner\n"); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h new file mode 100644 index 000000000000..41bac8856b50 --- /dev/null +++ b/drivers/media/video/cx18/cx18-gpio.h @@ -0,0 +1,24 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void cx18_gpio_init(struct cx18 *cx); +int cx18_reset_tuner_gpio(void *dev, int cmd, int value); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c new file mode 100644 index 000000000000..18c88d1e4833 --- /dev/null +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -0,0 +1,431 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "cx18-av-core.h" + +#include <media/ir-kbd-i2c.h> + +#define CX18_REG_I2C_1_WR 0xf15000 +#define CX18_REG_I2C_1_RD 0xf15008 +#define CX18_REG_I2C_2_WR 0xf25100 +#define CX18_REG_I2C_2_RD 0xf25108 + +#define SETSCL_BIT 0x0001 +#define SETSDL_BIT 0x0002 +#define GETSCL_BIT 0x0004 +#define GETSDL_BIT 0x0008 + +#ifndef I2C_ADAP_CLASS_TV_ANALOG +#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG +#endif + +#define CX18_CS5345_I2C_ADDR 0x4c + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_driverids[] = { + I2C_DRIVERID_TUNER, + I2C_DRIVERID_TVEEPROM, + I2C_DRIVERID_CS5345, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0 /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_addrs[] = { + 0, + 0, + CX18_CS5345_I2C_ADDR, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0, /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +/* This might well become a card-specific array */ +static const u8 hw_bus[] = { + 0, + 0, + 0, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0, /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +static const char * const hw_drivernames[] = { + "tuner", + "tveeprom", + "cs5345", + "gpio", + "cx23418", +}; + +int cx18_i2c_register(struct cx18 *cx, unsigned idx) +{ + struct i2c_board_info info; + struct i2c_client *c; + u8 id, bus; + int i; + + CX18_DEBUG_I2C("i2c client register\n"); + if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) + return -1; + id = hw_driverids[idx]; + bus = hw_bus[idx]; + memset(&info, 0, sizeof(info)); + strlcpy(info.driver_name, hw_drivernames[idx], + sizeof(info.driver_name)); + info.addr = hw_addrs[idx]; + for (i = 0; i < I2C_CLIENTS_MAX; i++) + if (cx->i2c_clients[i] == NULL) + break; + + if (i == I2C_CLIENTS_MAX) { + CX18_ERR("insufficient room for new I2C client!\n"); + return -ENOMEM; + } + + if (id != I2C_DRIVERID_TUNER) { + c = i2c_new_device(&cx->i2c_adap[bus], &info); + if (c->driver == NULL) + i2c_unregister_device(c); + else + cx->i2c_clients[i] = c; + return cx->i2c_clients[i] ? 0 : -ENODEV; + } + + /* special tuner handling */ + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + return 0; +} + +static int attach_inform(struct i2c_client *client) +{ + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + int i; + struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter); + + CX18_DEBUG_I2C("i2c client detach\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (cx->i2c_clients[i] == client) { + cx->i2c_clients[i] = NULL; + break; + } + } + CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n", + client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + + return 0; +} + +static void cx18_setscl(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = read_reg(addr); + + if (state) + write_reg_sync(r | SETSCL_BIT, addr); + else + write_reg_sync(r & ~SETSCL_BIT, addr); +} + +static void cx18_setsda(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = read_reg(addr); + + if (state) + write_reg_sync(r | SETSDL_BIT, addr); + else + write_reg_sync(r & ~SETSDL_BIT, addr); +} + +static int cx18_getscl(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return read_reg(addr) & GETSCL_BIT; +} + +static int cx18_getsda(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return read_reg(addr) & GETSDL_BIT; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter cx18_i2c_adap_template = { + .name = "cx18 i2c driver", + .id = I2C_HW_B_CX2341X, + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .client_register = attach_inform, + .client_unregister = detach_inform, + .owner = THIS_MODULE, +}; + +#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ +#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ + +static struct i2c_algo_bit_data cx18_i2c_algo_template = { + .setsda = cx18_setsda, + .setscl = cx18_setscl, + .getsda = cx18_getsda, + .getscl = cx18_getscl, + .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/ + .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ +}; + +static struct i2c_client cx18_i2c_client_template = { + .name = "cx18 internal", +}; + +int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg) +{ + struct i2c_client *client; + int retval; + int i; + + CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + client = cx->i2c_clients[i]; + if (client == NULL || client->driver == NULL || + client->driver->command == NULL) + continue; + if (addr == client->addr) { + retval = client->driver->command(client, cmd, arg); + return retval; + } + } + if (cmd != VIDIOC_G_CHIP_IDENT) + CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n", + addr, cmd); + return -ENODEV; +} + +/* Find the i2c device based on the driver ID and return + its i2c address or -ENODEV if no matching device was found. */ +static int cx18_i2c_id_addr(struct cx18 *cx, u32 id) +{ + struct i2c_client *client; + int retval = -ENODEV; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + client = cx->i2c_clients[i]; + if (client == NULL || client->driver == NULL) + continue; + if (id == client->driver->id) { + retval = client->addr; + break; + } + } + return retval; +} + +/* Find the i2c device name matching the DRIVERID */ +static const char *cx18_i2c_id_name(u32 id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (hw_driverids[i] == id) + return hw_drivernames[i]; + return "unknown device"; +} + +/* Find the i2c device name matching the CX18_HW_ flag */ +static const char *cx18_i2c_hw_name(u32 hw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (1 << i == hw) + return hw_drivernames[i]; + return "unknown device"; +} + +/* Find the i2c device matching the CX18_HW_ flag and return + its i2c address or -ENODEV if no matching device was found. */ +int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (1 << i == hw) + return cx18_i2c_id_addr(cx, hw_driverids[i]); + return -ENODEV; +} + +/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing. + If hw == CX18_HW_GPIO then call the gpio handler. */ +int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg) +{ + int addr; + + if (hw == CX18_HW_GPIO || hw == 0) + return 0; + if (hw == CX18_HW_CX23418) + return cx18_av_cmd(cx, cmd, arg); + + addr = cx18_i2c_hw_addr(cx, hw); + if (addr < 0) { + CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n", + hw, cx18_i2c_hw_name(hw), cmd); + return addr; + } + return cx18_call_i2c_client(cx, addr, cmd, arg); +} + +/* Calls i2c device based on I2C driver ID. */ +int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg) +{ + int addr; + + addr = cx18_i2c_id_addr(cx, id); + if (addr < 0) { + if (cmd != VIDIOC_G_CHIP_IDENT) + CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n", + id, cx18_i2c_id_name(id), cmd); + return addr; + } + return cx18_call_i2c_client(cx, addr, cmd, arg); +} + +/* broadcast cmd for all I2C clients and for the gpio subsystem */ +void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg) +{ + if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) { + CX18_ERR("adapter is not set\n"); + return; + } + cx18_av_cmd(cx, cmd, arg); + i2c_clients_command(&cx->i2c_adap[0], cmd, arg); + i2c_clients_command(&cx->i2c_adap[1], cmd, arg); +} + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c init\n"); + + for (i = 0; i < 2; i++) { + memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, + sizeof(struct i2c_adapter)); + memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, + sizeof(struct i2c_algo_bit_data)); + cx->i2c_algo_cb_data[i].cx = cx; + cx->i2c_algo_cb_data[i].bus_index = i; + cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; + cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; + + sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), + " #%d-%d", cx->num, i); + i2c_set_adapdata(&cx->i2c_adap[i], cx); + + memcpy(&cx->i2c_client[i], &cx18_i2c_client_template, + sizeof(struct i2c_client)); + sprintf(cx->i2c_client[i].name + + strlen(cx->i2c_client[i].name), "%d", i); + cx->i2c_client[i].adapter = &cx->i2c_adap[i]; + cx->i2c_adap[i].dev.parent = &cx->dev->dev; + } + + if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) { + /* Reset/Unreset I2C hardware block */ + write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */ + write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */ + } + /* courtesy of Steven Toth <stoth@hauppauge.com> */ + write_reg_sync(0x00c00000, 0xc7001c); + mdelay(10); + write_reg_sync(0x00c000c0, 0xc7001c); + mdelay(10); + write_reg_sync(0x00c00000, 0xc7001c); + + write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */ + write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */ + + /* Hw I2C1 Clock Freq ~100kHz */ + write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR); + cx18_setscl(&cx->i2c_algo_cb_data[0], 1); + cx18_setsda(&cx->i2c_algo_cb_data[0], 1); + + /* Hw I2C2 Clock Freq ~100kHz */ + write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR); + cx18_setscl(&cx->i2c_algo_cb_data[1], 1); + cx18_setsda(&cx->i2c_algo_cb_data[1], 1); + + return i2c_bit_add_bus(&cx->i2c_adap[0]) || + i2c_bit_add_bus(&cx->i2c_adap[1]); +} + +void exit_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c exit\n"); + write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR); + write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR); + + for (i = 0; i < 2; i++) { + i2c_del_adapter(&cx->i2c_adap[i]); + } +} + +/* + Hauppauge HVR1600 should have: + 32 cx24227 + 98 unknown + a0 eeprom + c2 tuner + e? zilog ir + */ diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h new file mode 100644 index 000000000000..113c3f9a2cc0 --- /dev/null +++ b/drivers/media/video/cx18/cx18-i2c.h @@ -0,0 +1,33 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw); +int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg); +int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg); +int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg); +void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg); +int cx18_i2c_register(struct cx18 *cx, unsigned idx); + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx); +void exit_cx18_i2c(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c new file mode 100644 index 000000000000..dbdcb86ec5aa --- /dev/null +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -0,0 +1,851 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-fileops.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-video.h" +#include "cx18-streams.h" +#include "cx18-ioctl.h" +#include "cx18-gpio.h" +#include "cx18-controls.h" +#include "cx18-cards.h" +#include "cx18-av-core.h" +#include <media/tveeprom.h> +#include <media/v4l2-chip-ident.h> +#include <linux/i2c-id.h> + +u16 cx18_service2vbi(int type) +{ + switch (type) { + case V4L2_SLICED_TELETEXT_B: + return CX18_SLICED_TYPE_TELETEXT_B; + case V4L2_SLICED_CAPTION_525: + return CX18_SLICED_TYPE_CAPTION_525; + case V4L2_SLICED_WSS_625: + return CX18_SLICED_TYPE_WSS_625; + case V4L2_SLICED_VPS: + return CX18_SLICED_TYPE_VPS; + default: + return 0; + } +} + +static int valid_service_line(int field, int line, int is_pal) +{ + return (is_pal && line >= 6 && (line != 23 || field == 0)) || + (!is_pal && line >= 10 && line < 22); +} + +static u16 select_service_from_set(int field, int line, u16 set, int is_pal) +{ + u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); + int i; + + set = set & valid_set; + if (set == 0 || !valid_service_line(field, line, is_pal)) + return 0; + if (!is_pal) { + if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) + return V4L2_SLICED_CAPTION_525; + } else { + if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) + return V4L2_SLICED_VPS; + if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) + return V4L2_SLICED_WSS_625; + if (line == 23) + return 0; + } + for (i = 0; i < 32; i++) { + if ((1 << i) & set) + return 1 << i; + } + return 0; +} + +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + u16 set = fmt->service_set; + int f, l; + + fmt->service_set = 0; + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); + } +} + +static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); + set |= fmt->service_lines[f][l]; + } + } + return set != 0; +} + +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + set |= fmt->service_lines[f][l]; + } + return set; +} + +static const struct { + v4l2_std_id std; + char *name; +} enum_stds[] = { + { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, + { V4L2_STD_PAL_DK, "PAL-DK" }, + { V4L2_STD_PAL_I, "PAL-I" }, + { V4L2_STD_PAL_M, "PAL-M" }, + { V4L2_STD_PAL_N, "PAL-N" }, + { V4L2_STD_PAL_Nc, "PAL-Nc" }, + { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, + { V4L2_STD_SECAM_DK, "SECAM-DK" }, + { V4L2_STD_SECAM_L, "SECAM-L" }, + { V4L2_STD_SECAM_LC, "SECAM-L'" }, + { V4L2_STD_NTSC_M, "NTSC-M" }, + { V4L2_STD_NTSC_M_JP, "NTSC-J" }, + { V4L2_STD_NTSC_M_KR, "NTSC-K" }, +}; + +static const struct v4l2_standard cx18_std_60hz = { + .frameperiod = {.numerator = 1001, .denominator = 30000}, + .framelines = 525, +}; + +static const struct v4l2_standard cx18_std_50hz = { + .frameperiod = { .numerator = 1, .denominator = 25 }, + .framelines = 625, +}; + +static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_register *regs = arg; + unsigned long flags; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + + spin_lock_irqsave(&cx18_cards_lock, flags); + if (cmd == VIDIOC_DBG_G_REGISTER) + regs->val = read_enc(regs->reg); + else + write_enc(regs->val, regs->reg); + spin_unlock_irqrestore(&cx18_cards_lock, flags); + return 0; +} + +static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt) +{ + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + fmt->fmt.pix.width = cx->params.width; + fmt->fmt.pix.height = cx->params.height; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; + if (streamtype == CX18_ENC_STREAM_TYPE_YUV) { + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + fmt->fmt.pix.sizeimage = + fmt->fmt.pix.height * fmt->fmt.pix.width + + fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); + } else { + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + fmt->fmt.pix.sizeimage = 128 * 1024; + } + break; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + fmt->fmt.vbi.sampling_rate = 27000000; + fmt->fmt.vbi.offset = 248; + fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4; + fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + fmt->fmt.vbi.start[0] = cx->vbi.start[0]; + fmt->fmt.vbi.start[1] = cx->vbi.start[1]; + fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count; + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + { + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); + + cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); + vbifmt->service_set = cx18_get_service_set(vbifmt); + break; + } + default: + return -EINVAL; + } + return 0; +} + +static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, + struct v4l2_format *fmt, int set_fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + u16 set; + + /* set window size */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + if (w > 720) + w = 720; + else if (w < 1) + w = 1; + if (h > (cx->is_50hz ? 576 : 480)) + h = (cx->is_50hz ? 576 : 480); + else if (h < 2) + h = 2; + cx18_get_fmt(cx, streamtype, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + + if (!set_fmt || (cx->params.width == w && cx->params.height == h)) + return 0; + if (atomic_read(&cx->capturing) > 0) + return -EBUSY; + + cx->params.width = w; + cx->params.height = h; + if (w != 720 || h != (cx->is_50hz ? 576 : 480)) + cx->params.video_temporal_filter = 0; + else + cx->params.video_temporal_filter = 8; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + return cx18_get_fmt(cx, streamtype, fmt); + } + + /* set raw VBI format */ + if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set && + atomic_read(&cx->capturing) > 0) + return -EBUSY; + if (set_fmt) { + cx->vbi.sliced_in->service_set = 0; + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + } + return cx18_get_fmt(cx, streamtype, fmt); + } + + /* any else but sliced VBI capture is an error */ + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + + /* TODO: implement sliced VBI, for now silently return 0 */ + return 0; + + /* set sliced VBI capture format */ + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + + if (vbifmt->service_set) + cx18_expand_service_set(vbifmt, cx->is_50hz); + set = check_service_set(vbifmt, cx->is_50hz); + vbifmt->service_set = cx18_get_service_set(vbifmt); + + if (!set_fmt) + return 0; + if (set == 0) + return -EINVAL; + if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0) + return -EBUSY; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); + return 0; +} + +static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + struct v4l2_register *reg = arg; + + switch (cmd) { + /* ioctls to allow direct access to the encoder registers for testing */ + case VIDIOC_DBG_G_REGISTER: + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + + case VIDIOC_DBG_S_REGISTER: + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + + case VIDIOC_G_CHIP_IDENT: { + struct v4l2_chip_ident *chip = arg; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (reg->match_type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { + struct v4l2_chip_ident *chip = arg; + + chip->ident = V4L2_IDENT_CX23418; + } + return 0; + } + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + return -EINVAL; + } + + case VIDIOC_INT_S_AUDIO_ROUTING: { + struct v4l2_routing *route = arg; + + cx18_audio_set_route(cx, route); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) +{ + struct cx18_open_id *id = NULL; + + if (filp) + id = (struct cx18_open_id *)filp->private_data; + + switch (cmd) { + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; + + *p = v4l2_prio_max(&cx->prio); + break; + } + + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; + + return v4l2_prio_change(&cx->prio, &id->prio, *prio); + } + + case VIDIOC_QUERYCAP:{ + struct v4l2_capability *vcap = arg; + + memset(vcap, 0, sizeof(*vcap)); + strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); + vcap->version = CX18_DRIVER_VERSION; /* version */ + vcap->capabilities = cx->v4l2_cap; /* capabilities */ + + /* reserved.. must set to 0! */ + vcap->reserved[0] = vcap->reserved[1] = + vcap->reserved[2] = vcap->reserved[3] = 0; + break; + } + + case VIDIOC_ENUMAUDIO:{ + struct v4l2_audio *vin = arg; + + return cx18_get_audio_input(cx, vin->index, vin); + } + + case VIDIOC_G_AUDIO:{ + struct v4l2_audio *vin = arg; + + vin->index = cx->audio_input; + return cx18_get_audio_input(cx, vin->index, vin); + } + + case VIDIOC_S_AUDIO:{ + struct v4l2_audio *vout = arg; + + if (vout->index >= cx->nof_audio_inputs) + return -EINVAL; + cx->audio_input = vout->index; + cx18_audio_set_io(cx); + break; + } + + case VIDIOC_ENUMINPUT:{ + struct v4l2_input *vin = arg; + + /* set it to defaults from our table */ + return cx18_get_input(cx, vin->index, vin); + } + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: { + struct v4l2_format *fmt = arg; + + return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT); + } + + case VIDIOC_G_FMT: { + struct v4l2_format *fmt = arg; + int type = fmt->type; + + memset(fmt, 0, sizeof(*fmt)); + fmt->type = type; + return cx18_get_fmt(cx, id->type, fmt); + } + + case VIDIOC_CROPCAP: { + struct v4l2_cropcap *cropcap = arg; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = cx->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; + cropcap->defrect = cropcap->bounds; + return 0; + } + + case VIDIOC_S_CROP: { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_S_CROP, arg); + } + + case VIDIOC_G_CROP: { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_G_CROP, arg); + } + + case VIDIOC_ENUM_FMT: { + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } + } + }; + struct v4l2_fmtdesc *fmt = arg; + enum v4l2_buf_type type = fmt->type; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + default: + return -EINVAL; + } + if (fmt->index > 1) + return -EINVAL; + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; + } + + case VIDIOC_G_INPUT:{ + *(int *)arg = cx->active_input; + break; + } + + case VIDIOC_S_INPUT:{ + int inp = *(int *)arg; + + if (inp < 0 || inp >= cx->nof_inputs) + return -EINVAL; + + if (inp == cx->active_input) { + CX18_DEBUG_INFO("Input unchanged\n"); + break; + } + CX18_DEBUG_INFO("Changing input from %d to %d\n", + cx->active_input, inp); + + cx->active_input = inp; + /* Set the audio input to whatever is appropriate for the + input type. */ + cx->audio_input = cx->card->video_inputs[inp].audio_index; + + /* prevent others from messing with the streams until + we're finished changing inputs. */ + cx18_mute(cx); + cx18_video_set_io(cx); + cx18_audio_set_io(cx); + cx18_unmute(cx); + break; + } + + case VIDIOC_G_FREQUENCY:{ + struct v4l2_frequency *vf = arg; + + if (vf->tuner != 0) + return -EINVAL; + cx18_call_i2c_clients(cx, cmd, arg); + break; + } + + case VIDIOC_S_FREQUENCY:{ + struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; + + if (vf.tuner != 0) + return -EINVAL; + + cx18_mute(cx); + CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); + cx18_call_i2c_clients(cx, cmd, &vf); + cx18_unmute(cx); + break; + } + + case VIDIOC_ENUMSTD:{ + struct v4l2_standard *vs = arg; + int idx = vs->index; + + if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) + return -EINVAL; + + *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? + cx18_std_60hz : cx18_std_50hz; + vs->index = idx; + vs->id = enum_stds[idx].std; + strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); + break; + } + + case VIDIOC_G_STD:{ + *(v4l2_std_id *) arg = cx->std; + break; + } + + case VIDIOC_S_STD: { + v4l2_std_id std = *(v4l2_std_id *) arg; + + if ((std & V4L2_STD_ALL) == 0) + return -EINVAL; + + if (std == cx->std) + break; + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || + atomic_read(&cx->capturing) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; + } + + cx->std = std; + cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; + cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; + cx->params.width = 720; + cx->params.height = cx->is_50hz ? 576 : 480; + cx->vbi.count = cx->is_50hz ? 18 : 12; + cx->vbi.start[0] = cx->is_50hz ? 6 : 10; + cx->vbi.start[1] = cx->is_50hz ? 318 : 273; + cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; + CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std); + + /* Tuner */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + break; + } + + case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ + struct v4l2_tuner *vt = arg; + + if (vt->index != 0) + return -EINVAL; + + cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); + break; + } + + case VIDIOC_G_TUNER: { + struct v4l2_tuner *vt = arg; + + if (vt->index != 0) + return -EINVAL; + + memset(vt, 0, sizeof(*vt)); + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; + } + break; + } + + case VIDIOC_G_SLICED_VBI_CAP: { + struct v4l2_sliced_vbi_cap *cap = arg; + int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + enum v4l2_buf_type type = cap->type; + + memset(cap, 0, sizeof(*cap)); + cap->type = type; + if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + if (valid_service_line(f, l, cx->is_50hz)) + cap->service_lines[f][l] = set; + } + } + return 0; + } + return -EINVAL; + } + + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: { + struct v4l2_encoder_cmd *enc = arg; + int try = cmd == VIDIOC_TRY_ENCODER_CMD; + + memset(&enc->raw, 0, sizeof(enc->raw)); + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + enc->flags = 0; + if (try) + return 0; + return cx18_start_capture(id); + + case V4L2_ENC_CMD_STOP: + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + if (try) + return 0; + cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + return 0; + + case V4L2_ENC_CMD_PAUSE: + enc->flags = 0; + if (try) + return 0; + if (!atomic_read(&cx->capturing)) + return -EPERM; + if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_mute(cx); + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); + break; + + case V4L2_ENC_CMD_RESUME: + enc->flags = 0; + if (try) + return 0; + if (!atomic_read(&cx->capturing)) + return -EPERM; + if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); + cx18_unmute(cx); + break; + default: + return -EINVAL; + } + break; + } + + case VIDIOC_LOG_STATUS: + { + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); + if (cx->hw_flags & CX18_HW_TVEEPROM) { + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + } + cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); + cx18_get_input(cx, cx->active_input, &vidin); + cx18_get_audio_input(cx, cx->audio_input, &audin); + CX18_INFO("Video Input: %s\n", vidin.name); + CX18_INFO("Audio Input: %s\n", audin.name); + CX18_INFO("Tuner: %s\n", + test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? + "Radio" : "TV"); + cx2341x_log_status(&cx->params, cx->name); + CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL || s->buffers == 0) + continue; + CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", + s->name, s->s_flags, + (s->buffers - s->q_free.buffers) * 100 / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); + } + CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", + (long long)cx->mpg_data_received, + (long long)cx->vbi_data_inserted); + CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, void *arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + int ret; + + /* check priority */ + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FMT: + case VIDIOC_S_CROP: + case VIDIOC_S_EXT_CTRLS: + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + } + + switch (cmd) { + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + case VIDIOC_G_CHIP_IDENT: + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_RESET: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_debug_ioctls(filp, cmd, arg); + + case VIDIOC_G_PRIORITY: + case VIDIOC_S_PRIORITY: + case VIDIOC_QUERYCAP: + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + case VIDIOC_ENUM_FMT: + case VIDIOC_CROPCAP: + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_ENUMSTD: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_S_TUNER: + case VIDIOC_G_TUNER: + case VIDIOC_ENUMAUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_G_AUDIO: + case VIDIOC_G_SLICED_VBI_CAP: + case VIDIOC_LOG_STATUS: + case VIDIOC_G_ENC_INDEX: + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_v4l2_ioctls(cx, filp, cmd, arg); + + case VIDIOC_QUERYMENU: + case VIDIOC_QUERYCTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_CTRL: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_control_ioctls(cx, cmd, arg); + + case 0x00005401: /* Handle isatty() calls */ + return -EINVAL; + default: + return v4l_compat_translate_ioctl(inode, filp, cmd, arg, + cx18_v4l2_do_ioctl); + } + return 0; +} + +int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + int res; + + mutex_lock(&cx->serialize_lock); + res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl); + mutex_unlock(&cx->serialize_lock); + return res; +} diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h new file mode 100644 index 000000000000..9f4c7eb2897f --- /dev/null +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -0,0 +1,30 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +u16 cx18_service2vbi(int type); +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); +int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, + void *arg); diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c new file mode 100644 index 000000000000..6e14f8bda559 --- /dev/null +++ b/drivers/media/video/cx18/cx18-irq.c @@ -0,0 +1,179 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-firmware.h" +#include "cx18-fileops.h" +#include "cx18-queue.h" +#include "cx18-irq.h" +#include "cx18-ioctl.h" +#include "cx18-mailbox.h" +#include "cx18-vbi.h" +#include "cx18-scb.h" + +#define DMA_MAGIC_COOKIE 0x000001fe + +static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) +{ + u32 handle = mb->args[0]; + struct cx18_stream *s = NULL; + struct cx18_buffer *buf; + u32 off; + int i; + int id; + + for (i = 0; i < CX18_MAX_STREAMS; i++) { + s = &cx->streams[i]; + if ((handle == s->handle) && (s->dvb.enabled)) + break; + if (s->v4l2dev && handle == s->handle) + break; + } + if (i == CX18_MAX_STREAMS) { + CX18_WARN("DMA done for unknown handle %d for stream %s\n", + handle, s->name); + mb->error = CXERR_NOT_OPEN; + mb->cmd = 0; + cx18_mb_ack(cx, mb); + return; + } + + off = mb->args[1]; + if (mb->args[2] != 1) + CX18_WARN("Ack struct = %d for %s\n", + mb->args[2], s->name); + id = read_enc(off); + buf = cx18_queue_find_buf(s, id, read_enc(off + 4)); + CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); + if (buf) { + cx18_buf_sync_for_cpu(s, buf); + if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { + /* process the buffer here */ + CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n", + buf->bytesused); + + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + + cx18_buf_sync_for_device(s, buf); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } else + set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); + } else { + CX18_WARN("Could not find buf %d for stream %s\n", + read_enc(off), s->name); + } + mb->error = 0; + mb->cmd = 0; + cx18_mb_ack(cx, mb); + wake_up(&cx->dma_waitq); + if (s->id != -1) + wake_up(&s->waitq); +} + +static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) +{ + char str[256] = { 0 }; + char *p; + + if (mb->args[1]) { + setup_page(mb->args[1]); + memcpy_fromio(str, cx->enc_mem + mb->args[1], 252); + str[252] = 0; + } + cx18_mb_ack(cx, mb); + CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); + p = strchr(str, '.'); + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) + CX18_INFO("FW version: %s\n", p - 1); +} + +static void hpu_cmd(struct cx18 *cx, u32 sw1) +{ + struct cx18_mailbox mb; + + if (sw1 & IRQ_CPU_TO_EPU) { + memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb)); + mb.error = 0; + + switch (mb.cmd) { + case CX18_EPU_DMA_DONE: + epu_dma_done(cx, &mb); + break; + case CX18_EPU_DEBUG: + epu_debug(cx, &mb); + break; + default: + CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd); + break; + } + } + if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU)) + CX18_WARN("Unexpected interrupt %08x\n", sw1); +} + +irqreturn_t cx18_irq_handler(int irq, void *dev_id) +{ + struct cx18 *cx = (struct cx18 *)dev_id; + u32 sw1, sw1_mask; + u32 sw2, sw2_mask; + u32 hw2, hw2_mask; + + spin_lock(&cx->dma_reg_lock); + + hw2_mask = read_reg(HW2_INT_MASK5_PCI); + hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask; + sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; + sw2 = read_reg(SW2_INT_STATUS) & sw2_mask; + sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; + sw1 = read_reg(SW1_INT_STATUS) & sw1_mask; + + write_reg(sw2&sw2_mask, SW2_INT_STATUS); + write_reg(sw1&sw1_mask, SW1_INT_STATUS); + write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS); + + if (sw1 || sw2 || hw2) + CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + + /* To do: interrupt-based I2C handling + if (hw2 & 0x00c00000) { + } + */ + + if (sw2) { + if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack)) + wake_up(&cx->mb_cpu_waitq); + if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack)) + wake_up(&cx->mb_apu_waitq); + if (sw2 & cx->scb->epu2hpu_irq_ack) + wake_up(&cx->mb_epu_waitq); + if (sw2 & cx->scb->hpu2epu_irq_ack) + wake_up(&cx->mb_hpu_waitq); + } + + if (sw1) + hpu_cmd(cx, sw1); + spin_unlock(&cx->dma_reg_lock); + + return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE; +} diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h new file mode 100644 index 000000000000..379f704f5cba --- /dev/null +++ b/drivers/media/video/cx18/cx18-irq.h @@ -0,0 +1,37 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#define HW2_I2C1_INT (1 << 22) +#define HW2_I2C2_INT (1 << 23) +#define HW2_INT_CLR_STATUS 0xc730c4 +#define HW2_INT_MASK5_PCI 0xc730e4 +#define SW1_INT_SET 0xc73100 +#define SW1_INT_STATUS 0xc73104 +#define SW1_INT_ENABLE_PCI 0xc7311c +#define SW2_INT_SET 0xc73140 +#define SW2_INT_STATUS 0xc73144 +#define SW2_INT_ENABLE_PCI 0xc7315c + +irqreturn_t cx18_irq_handler(int irq, void *dev_id); + +void cx18_irq_work_handler(struct work_struct *work); +void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock); +void cx18_unfinished_dma(unsigned long arg); diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c new file mode 100644 index 000000000000..0c5f328bca54 --- /dev/null +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -0,0 +1,372 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include <stdarg.h> + +#include "cx18-driver.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-mailbox.h" + +#define API_FAST (1 << 2) /* Short timeout */ +#define API_SLOW (1 << 3) /* Additional 300ms timeout */ + +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + +struct cx18_api_info { + u32 cmd; + u8 flags; /* Flags, see above */ + u8 rpu; /* Processing unit */ + const char *name; /* The name of the command */ +}; + +#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } + +static const struct cx18_api_info api_info[] = { + /* MPEG encoder API */ + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_EPU_DEBUG, 0), + API_ENTRY(CPU, CX18_CREATE_TASK, 0), + API_ENTRY(CPU, CX18_DESTROY_TASK, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), + API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), + API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), + API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), + API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), + API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), + API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), + API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), + API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), + API_ENTRY(0, 0, 0), +}; + +static const struct cx18_api_info *find_api_info(u32 cmd) +{ + int i; + + for (i = 0; api_info[i].cmd; i++) + if (api_info[i].cmd == cmd) + return &api_info[i]; + return NULL; +} + +static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu, + u32 *state, u32 *irq, u32 *req) +{ + struct cx18_mailbox *mb = NULL; + int wait_count = 0; + u32 ack; + + switch (rpu) { + case APU: + mb = &cx->scb->epu2apu_mb; + *state = readl(&cx->scb->apu_state); + *irq = readl(&cx->scb->epu2apu_irq); + break; + + case CPU: + mb = &cx->scb->epu2cpu_mb; + *state = readl(&cx->scb->cpu_state); + *irq = readl(&cx->scb->epu2cpu_irq); + break; + + case HPU: + mb = &cx->scb->epu2hpu_mb; + *state = readl(&cx->scb->hpu_state); + *irq = readl(&cx->scb->epu2hpu_irq); + break; + } + + if (mb == NULL) + return mb; + + do { + *req = readl(&mb->request); + ack = readl(&mb->ack); + wait_count++; + } while (*req != ack && wait_count < 600); + + if (*req == ack) { + (*req)++; + if (*req == 0 || *req == 0xffffffff) + *req = 1; + return mb; + } + return NULL; +} + +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) +{ + const struct cx18_api_info *info = find_api_info(mb->cmd); + struct cx18_mailbox *ack_mb; + u32 ack_irq; + u8 rpu = CPU; + + if (info == NULL && mb->cmd) { + CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); + return -EINVAL; + } + if (info) + rpu = info->rpu; + + switch (rpu) { + case HPU: + ack_irq = IRQ_EPU_TO_HPU_ACK; + ack_mb = &cx->scb->hpu2epu_mb; + break; + case APU: + ack_irq = IRQ_EPU_TO_APU_ACK; + ack_mb = &cx->scb->apu2epu_mb; + break; + case CPU: + ack_irq = IRQ_EPU_TO_CPU_ACK; + ack_mb = &cx->scb->cpu2epu_mb; + break; + default: + CX18_WARN("Unknown RPU for command %x\n", mb->cmd); + return -EINVAL; + } + + setup_page(SCB_OFFSET); + write_sync(mb->request, &ack_mb->ack); + write_reg(ack_irq, SW2_INT_SET); + return 0; +} + + +static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + const struct cx18_api_info *info = find_api_info(cmd); + u32 state = 0, irq = 0, req, oldreq, err; + struct cx18_mailbox *mb; + wait_queue_head_t *waitq; + int timeout = 100; + int cnt = 0; + int sig = 0; + int i; + + if (info == NULL) { + CX18_WARN("unknown cmd %x\n", cmd); + return -EINVAL; + } + + if (cmd == CX18_CPU_DE_SET_MDL) + CX18_DEBUG_HI_API("%s\n", info->name); + else + CX18_DEBUG_API("%s\n", info->name); + setup_page(SCB_OFFSET); + mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); + + if (mb == NULL) { + CX18_ERR("mb %s busy\n", info->name); + return -EBUSY; + } + + oldreq = req - 1; + writel(cmd, &mb->cmd); + for (i = 0; i < args; i++) + writel(data[i], &mb->args[i]); + writel(0, &mb->error); + writel(req, &mb->request); + + switch (info->rpu) { + case APU: waitq = &cx->mb_apu_waitq; break; + case CPU: waitq = &cx->mb_cpu_waitq; break; + case EPU: waitq = &cx->mb_epu_waitq; break; + case HPU: waitq = &cx->mb_hpu_waitq; break; + default: return -EINVAL; + } + if (info->flags & API_FAST) + timeout /= 2; + write_reg(irq, SW1_INT_SET); + + while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) { + if (cnt > 200 && !in_atomic()) + sig = cx18_msleep_timeout(10, 1); + cnt++; + } + if (sig) + return -EINTR; + if (cnt == 660) { + writel(oldreq, &mb->request); + CX18_ERR("mb %s failed\n", info->name); + return -EINVAL; + } + for (i = 0; i < MAX_MB_ARGUMENTS; i++) + data[i] = readl(&mb->args[i]); + err = readl(&mb->error); + if (!in_atomic() && (info->flags & API_SLOW)) + cx18_msleep_timeout(300, 0); + if (err) + CX18_DEBUG_API("mailbox error %08x for command %s\n", err, + info->name); + return err ? -EIO : 0; +} + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + int res = cx18_api_call(cx, cmd, args, data); + + /* Allow a single retry, probably already too late though. + If there is no free mailbox then that is usually an indication + of a more serious problem. */ + return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res; +} + +static int cx18_set_filter_param(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + u32 mode; + int ret; + + mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); + ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 1, mode, cx->spatial_strength); + mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 0, mode, cx->temporal_strength); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 2, cx->filter_mode >> 2, 0); + return ret; +} + +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx18 *cx = priv; + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; + + switch (cmd) { + case CX2341X_ENC_SET_OUTPUT_PORT: + return 0; + case CX2341X_ENC_SET_FRAME_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, + s->handle, 0, 0, 0, 0, data[0]); + case CX2341X_ENC_SET_FRAME_SIZE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, + s->handle, data[1], data[0]); + case CX2341X_ENC_SET_STREAM_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_ASPECT_RATIO: + return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, + s->handle, data[0]); + + case CX2341X_ENC_SET_GOP_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_GOP_CLOSURE: + return 0; + case CX2341X_ENC_SET_AUDIO_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + s->handle, data[0]); + case CX2341X_ENC_MUTE_AUDIO: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_BIT_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, + s->handle, data[0], data[1], data[2], data[3]); + case CX2341X_ENC_MUTE_VIDEO: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_FRAME_DROP_RATE: + return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, + s->handle, data[0]); + case CX2341X_ENC_MISC: + return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, + s->handle, data[0], data[1], data[2]); + case CX2341X_ENC_SET_DNR_FILTER_MODE: + cx->filter_mode = (data[0] & 3) | (data[1] << 2); + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_DNR_FILTER_PROPS: + cx->spatial_strength = data[0]; + cx->temporal_strength = data[1]; + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_CORING_LEVELS: + return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, + s->handle, data[0], data[1], data[2], data[3]); + } + CX18_WARN("Unknown cmd %x\n", cmd); + return 0; +} + +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], + u32 cmd, int args, ...) +{ + va_list ap; + int i; + + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} + +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) +{ + u32 data[MAX_MB_ARGUMENTS]; + va_list ap; + int i; + + if (cx == NULL) { + CX18_ERR("cx == NULL (cmd=%x)\n", cmd); + return 0; + } + if (args > MAX_MB_ARGUMENTS) { + CX18_ERR("args too big (cmd=%x)\n", cmd); + args = MAX_MB_ARGUMENTS; + } + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h new file mode 100644 index 000000000000..d995641536b3 --- /dev/null +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -0,0 +1,73 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#ifndef _CX18_MAILBOX_H_ +#define _CX18_MAILBOX_H_ + +/* mailbox max args */ +#define MAX_MB_ARGUMENTS 6 +/* compatibility, should be same as the define in cx2341x.h */ +#define CX2341X_MBOX_MAX_DATA 16 + +#define MB_RESERVED_HANDLE_0 0 +#define MB_RESERVED_HANDLE_1 0xFFFFFFFF + +struct cx18; + +/* The cx18_mailbox struct is the mailbox structure which is used for passing + messages between processors */ +struct cx18_mailbox { + /* The sender sets a handle in 'request' after he fills the command. The + 'request' should be different than 'ack'. The sender, also, generates + an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the + receiver. */ + u32 request; + /* The receiver detects a new command when 'req' is different than 'ack'. + He sets 'ack' to the same value as 'req' to clear the command. He, also, + generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU + is the receiver. */ + u32 ack; + u32 reserved[6]; + /* 'cmd' identifies the command. The list of these commands are in + cx23418.h */ + u32 cmd; + /* Each command can have up to 6 arguments */ + u32 args[MAX_MB_ARGUMENTS]; + /* The return code can be one of the codes in the file cx23418.h. If the + command is completed successfuly, the error will be ERR_SYS_SUCCESS. + If it is pending, the code is ERR_SYS_PENDING. If it failed, the error + code would indicate the task from which the error originated and will + be one of the errors in cx23418.h. In that case, the following + applies ((error & 0xff) != 0). + If the command is pending, the return will be passed in a MB from the + receiver to the sender. 'req' will be returned in args[0] */ + u32 error; +}; + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, + int args, ...); +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]); +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb); + +#endif diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c new file mode 100644 index 000000000000..65af1bb507ca --- /dev/null +++ b/drivers/media/video/cx18/cx18-queue.c @@ -0,0 +1,282 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-streams.h" +#include "cx18-queue.h" +#include "cx18-scb.h" + +int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, + const char __user *src, int copybytes) +{ + if (s->buf_size - buf->bytesused < copybytes) + copybytes = s->buf_size - buf->bytesused; + if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) + return -EFAULT; + buf->bytesused += copybytes; + return copybytes; +} + +void cx18_buf_swap(struct cx18_buffer *buf) +{ + int i; + + for (i = 0; i < buf->bytesused; i += 4) + swab32s((u32 *)(buf->buf + i)); +} + +void cx18_queue_init(struct cx18_queue *q) +{ + INIT_LIST_HEAD(&q->list); + q->buffers = 0; + q->length = 0; + q->bytesused = 0; +} + +void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) +{ + unsigned long flags = 0; + + /* clear the buffer if it is going to be enqueued to the free queue */ + if (q == &s->q_free) { + buf->bytesused = 0; + buf->readpos = 0; + buf->b_flags = 0; + } + spin_lock_irqsave(&s->qlock, flags); + list_add_tail(&buf->list, &q->list); + q->buffers++; + q->length += s->buf_size; + q->bytesused += buf->bytesused - buf->readpos; + spin_unlock_irqrestore(&s->qlock, flags); +} + +struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) +{ + struct cx18_buffer *buf = NULL; + unsigned long flags = 0; + + spin_lock_irqsave(&s->qlock, flags); + if (!list_empty(&q->list)) { + buf = list_entry(q->list.next, struct cx18_buffer, list); + list_del_init(q->list.next); + q->buffers--; + q->length -= s->buf_size; + q->bytesused -= buf->bytesused - buf->readpos; + } + spin_unlock_irqrestore(&s->qlock, flags); + return buf; +} + +struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, + u32 bytesused) +{ + struct cx18 *cx = s->cx; + struct list_head *p; + + list_for_each(p, &s->q_free.list) { + struct cx18_buffer *buf = + list_entry(p, struct cx18_buffer, list); + + if (buf->id != id) + continue; + buf->bytesused = bytesused; + /* the transport buffers are handled differently, + so there is no need to move them to the full queue */ + if (s->type == CX18_ENC_STREAM_TYPE_TS) + return buf; + s->q_free.buffers--; + s->q_free.length -= s->buf_size; + s->q_full.buffers++; + s->q_full.length += s->buf_size; + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + return buf; + } + CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); + return NULL; +} + +static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *to, int clear, int full) +{ + struct cx18_buffer *buf = + list_entry(from->list.next, struct cx18_buffer, list); + + list_move_tail(from->list.next, &to->list); + from->buffers--; + from->length -= s->buf_size; + from->bytesused -= buf->bytesused - buf->readpos; + /* special handling for q_free */ + if (clear) + buf->bytesused = buf->readpos = buf->b_flags = 0; + else if (full) { + /* special handling for stolen buffers, assume + all bytes are used. */ + buf->bytesused = s->buf_size; + buf->readpos = buf->b_flags = 0; + } + to->buffers++; + to->length += s->buf_size; + to->bytesused += buf->bytesused - buf->readpos; +} + +/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. + If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. + If 'steal' != NULL, then buffers may also taken from that queue if + needed. + + The buffer is automatically cleared if it goes to the free queue. It is + also cleared if buffers need to be taken from the 'steal' queue and + the 'from' queue is the free queue. + + When 'from' is q_free, then needed_bytes is compared to the total + available buffer length, otherwise needed_bytes is compared to the + bytesused value. For the 'steal' queue the total available buffer + length is always used. + + -ENOMEM is returned if the buffers could not be obtained, 0 if all + buffers where obtained from the 'from' list and if non-zero then + the number of stolen buffers is returned. */ +int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes) +{ + unsigned long flags; + int rc = 0; + int from_free = from == &s->q_free; + int to_free = to == &s->q_free; + int bytes_available; + + spin_lock_irqsave(&s->qlock, flags); + if (needed_bytes == 0) { + from_free = 1; + needed_bytes = from->length; + } + + bytes_available = from_free ? from->length : from->bytesused; + bytes_available += steal ? steal->length : 0; + + if (bytes_available < needed_bytes) { + spin_unlock_irqrestore(&s->qlock, flags); + return -ENOMEM; + } + if (from_free) { + u32 old_length = to->length; + + while (to->length - old_length < needed_bytes) { + if (list_empty(&from->list)) + from = steal; + if (from == steal) + rc++; /* keep track of 'stolen' buffers */ + cx18_queue_move_buf(s, from, to, 1, 0); + } + } else { + u32 old_bytesused = to->bytesused; + + while (to->bytesused - old_bytesused < needed_bytes) { + if (list_empty(&from->list)) + from = steal; + if (from == steal) + rc++; /* keep track of 'stolen' buffers */ + cx18_queue_move_buf(s, from, to, to_free, rc); + } + } + spin_unlock_irqrestore(&s->qlock, flags); + return rc; +} + +void cx18_flush_queues(struct cx18_stream *s) +{ + cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0); + cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0); +} + +int cx18_stream_alloc(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int i; + + if (s->buffers == 0) + return 0; + + CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n", + s->name, s->buffers, s->buf_size, + s->buffers * s->buf_size / 1024); + + if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - + (char *)cx->scb) > SCB_RESERVED_SIZE) { + unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE - + ((char *)cx->scb->cpu_mdl)); + + CX18_ERR("Too many buffers, cannot fit in SCB area\n"); + CX18_ERR("Max buffers = %zd\n", + bufsz / sizeof(struct cx18_mdl)); + return -ENOMEM; + } + + s->mdl_offset = cx->mdl_offset; + + /* allocate stream buffers. Initially all buffers are in q_free. */ + for (i = 0; i < s->buffers; i++) { + struct cx18_buffer *buf = + kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL); + + if (buf == NULL) + break; + buf->buf = kmalloc(s->buf_size, GFP_KERNEL); + if (buf->buf == NULL) { + kfree(buf); + break; + } + buf->id = cx->buffer_id++; + INIT_LIST_HEAD(&buf->list); + buf->dma_handle = pci_map_single(s->cx->dev, + buf->buf, s->buf_size, s->dma); + cx18_buf_sync_for_cpu(s, buf); + cx18_enqueue(s, buf, &s->q_free); + } + if (i == s->buffers) { + cx->mdl_offset += s->buffers; + return 0; + } + CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); + cx18_stream_free(s); + return -ENOMEM; +} + +void cx18_stream_free(struct cx18_stream *s) +{ + struct cx18_buffer *buf; + + /* move all buffers to q_free */ + cx18_flush_queues(s); + + /* empty q_free */ + while ((buf = cx18_dequeue(s, &s->q_free))) { + pci_unmap_single(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); + kfree(buf->buf); + kfree(buf); + } +} diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h new file mode 100644 index 000000000000..f86c8a6fa6e7 --- /dev/null +++ b/drivers/media/video/cx18/cx18-queue.h @@ -0,0 +1,59 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#define CX18_DMA_UNMAPPED ((u32) -1) + +/* cx18_buffer utility functions */ + +static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); +} + +static inline void cx18_buf_sync_for_device(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); +} + +int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, + const char __user *src, int copybytes); +void cx18_buf_swap(struct cx18_buffer *buf); + +/* cx18_queue utility functions */ +void cx18_queue_init(struct cx18_queue *q); +void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q); +struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); +int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes); +struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, + u32 bytesused); +void cx18_flush_queues(struct cx18_stream *s); + +/* cx18_stream utility functions */ +int cx18_stream_alloc(struct cx18_stream *s); +void cx18_stream_free(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c new file mode 100644 index 000000000000..30bc803e30da --- /dev/null +++ b/drivers/media/video/cx18/cx18-scb.c @@ -0,0 +1,121 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-scb.h" + +void cx18_init_scb(struct cx18 *cx) +{ + setup_page(SCB_OFFSET); + memset_io(cx->scb, 0, 0x10000); + + writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq); + writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack); + writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq); + writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack); + writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq); + writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack); + writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq); + writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack); + + writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq); + writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack); + writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq); + writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack); + writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq); + writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack); + writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq); + writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack); + + writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq); + writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack); + writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq); + writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack); + writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq); + writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack); + writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq); + writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack); + + writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq); + writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack); + writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq); + writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack); + writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq); + writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack); + writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq); + writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack); + + writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq); + writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack); + writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq); + writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack); + writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq); + writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack); + writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq); + writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack); + + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb), + &cx->scb->apu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb), + &cx->scb->hpu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb), + &cx->scb->ppu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb), + &cx->scb->epu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb), + &cx->scb->cpu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb), + &cx->scb->hpu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb), + &cx->scb->ppu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb), + &cx->scb->epu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb), + &cx->scb->cpu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb), + &cx->scb->apu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb), + &cx->scb->ppu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb), + &cx->scb->epu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb), + &cx->scb->cpu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb), + &cx->scb->apu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb), + &cx->scb->hpu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb), + &cx->scb->epu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb), + &cx->scb->cpu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb), + &cx->scb->apu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb), + &cx->scb->hpu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb), + &cx->scb->ppu2epu_mb_offset); + + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), + &cx->scb->ipc_offset); + + writel(1, &cx->scb->hpu_state); + writel(1, &cx->scb->epu_state); +} diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h new file mode 100644 index 000000000000..86b4cb15d163 --- /dev/null +++ b/drivers/media/video/cx18/cx18-scb.h @@ -0,0 +1,285 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#ifndef CX18_SCB_H +#define CX18_SCB_H + +#include "cx18-mailbox.h" + +/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts + are in the SW1 register. */ + +#define IRQ_APU_TO_CPU 0x00000001 +#define IRQ_CPU_TO_APU_ACK 0x00000001 +#define IRQ_HPU_TO_CPU 0x00000002 +#define IRQ_CPU_TO_HPU_ACK 0x00000002 +#define IRQ_PPU_TO_CPU 0x00000004 +#define IRQ_CPU_TO_PPU_ACK 0x00000004 +#define IRQ_EPU_TO_CPU 0x00000008 +#define IRQ_CPU_TO_EPU_ACK 0x00000008 + +#define IRQ_CPU_TO_APU 0x00000010 +#define IRQ_APU_TO_CPU_ACK 0x00000010 +#define IRQ_HPU_TO_APU 0x00000020 +#define IRQ_APU_TO_HPU_ACK 0x00000020 +#define IRQ_PPU_TO_APU 0x00000040 +#define IRQ_APU_TO_PPU_ACK 0x00000040 +#define IRQ_EPU_TO_APU 0x00000080 +#define IRQ_APU_TO_EPU_ACK 0x00000080 + +#define IRQ_CPU_TO_HPU 0x00000100 +#define IRQ_HPU_TO_CPU_ACK 0x00000100 +#define IRQ_APU_TO_HPU 0x00000200 +#define IRQ_HPU_TO_APU_ACK 0x00000200 +#define IRQ_PPU_TO_HPU 0x00000400 +#define IRQ_HPU_TO_PPU_ACK 0x00000400 +#define IRQ_EPU_TO_HPU 0x00000800 +#define IRQ_HPU_TO_EPU_ACK 0x00000800 + +#define IRQ_CPU_TO_PPU 0x00001000 +#define IRQ_PPU_TO_CPU_ACK 0x00001000 +#define IRQ_APU_TO_PPU 0x00002000 +#define IRQ_PPU_TO_APU_ACK 0x00002000 +#define IRQ_HPU_TO_PPU 0x00004000 +#define IRQ_PPU_TO_HPU_ACK 0x00004000 +#define IRQ_EPU_TO_PPU 0x00008000 +#define IRQ_PPU_TO_EPU_ACK 0x00008000 + +#define IRQ_CPU_TO_EPU 0x00010000 +#define IRQ_EPU_TO_CPU_ACK 0x00010000 +#define IRQ_APU_TO_EPU 0x00020000 +#define IRQ_EPU_TO_APU_ACK 0x00020000 +#define IRQ_HPU_TO_EPU 0x00040000 +#define IRQ_EPU_TO_HPU_ACK 0x00040000 +#define IRQ_PPU_TO_EPU 0x00080000 +#define IRQ_EPU_TO_PPU_ACK 0x00080000 + +#define SCB_OFFSET 0xDC0000 + +/* If Firmware uses fixed memory map, it shall not allocate the area + between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */ +#define SCB_RESERVED_SIZE 0x10000 + + +/* This structure is used by EPU to provide memory descriptors in its memory */ +struct cx18_mdl { + u32 paddr; /* Physical address of a buffer segment */ + u32 length; /* Length of the buffer segment */ +}; + +/* This structure is used by CPU to provide completed buffers information */ +struct cx18_mdl_ack { + u32 id; /* ID of a completed MDL */ + u32 data_used; /* Total data filled in the MDL for buffer 'id' */ +}; + +struct cx18_scb { + /* These fields form the System Control Block which is used at boot time + for localizing the IPC data as well as the code positions for all + processors. The offsets are from the start of this struct. */ + + /* Offset where to find the Inter-Processor Communication data */ + u32 ipc_offset; + u32 reserved01[7]; + /* Offset where to find the start of the CPU code */ + u32 cpu_code_offset; + u32 reserved02[3]; + /* Offset where to find the start of the APU code */ + u32 apu_code_offset; + u32 reserved03[3]; + /* Offset where to find the start of the HPU code */ + u32 hpu_code_offset; + u32 reserved04[3]; + /* Offset where to find the start of the PPU code */ + u32 ppu_code_offset; + u32 reserved05[3]; + + /* These fields form Inter-Processor Communication data which is used + by all processors to locate the information needed for communicating + with other processors */ + + /* Fields for CPU: */ + + /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */ + u32 cpu_state; + u32 reserved1[7]; + /* Offset to the mailbox used for sending commands from APU to CPU */ + u32 apu2cpu_mb_offset; + /* Value to write to register SW1 register set (0xC7003100) after the + command is ready */ + u32 apu2cpu_irq; + /* Value to write to register SW2 register set (0xC7003140) after the + command is cleared */ + u32 apu2cpu_irq_ack; + u32 reserved2[13]; + + u32 hpu2cpu_mb_offset; + u32 hpu2cpu_irq; + u32 hpu2cpu_irq_ack; + u32 reserved3[13]; + + u32 ppu2cpu_mb_offset; + u32 ppu2cpu_irq; + u32 ppu2cpu_irq_ack; + u32 reserved4[13]; + + u32 epu2cpu_mb_offset; + u32 epu2cpu_irq; + u32 epu2cpu_irq_ack; + u32 reserved5[13]; + u32 reserved6[8]; + + /* Fields for APU: */ + + u32 apu_state; + u32 reserved11[7]; + u32 cpu2apu_mb_offset; + u32 cpu2apu_irq; + u32 cpu2apu_irq_ack; + u32 reserved12[13]; + + u32 hpu2apu_mb_offset; + u32 hpu2apu_irq; + u32 hpu2apu_irq_ack; + u32 reserved13[13]; + + u32 ppu2apu_mb_offset; + u32 ppu2apu_irq; + u32 ppu2apu_irq_ack; + u32 reserved14[13]; + + u32 epu2apu_mb_offset; + u32 epu2apu_irq; + u32 epu2apu_irq_ack; + u32 reserved15[13]; + u32 reserved16[8]; + + /* Fields for HPU: */ + + u32 hpu_state; + u32 reserved21[7]; + u32 cpu2hpu_mb_offset; + u32 cpu2hpu_irq; + u32 cpu2hpu_irq_ack; + u32 reserved22[13]; + + u32 apu2hpu_mb_offset; + u32 apu2hpu_irq; + u32 apu2hpu_irq_ack; + u32 reserved23[13]; + + u32 ppu2hpu_mb_offset; + u32 ppu2hpu_irq; + u32 ppu2hpu_irq_ack; + u32 reserved24[13]; + + u32 epu2hpu_mb_offset; + u32 epu2hpu_irq; + u32 epu2hpu_irq_ack; + u32 reserved25[13]; + u32 reserved26[8]; + + /* Fields for PPU: */ + + u32 ppu_state; + u32 reserved31[7]; + u32 cpu2ppu_mb_offset; + u32 cpu2ppu_irq; + u32 cpu2ppu_irq_ack; + u32 reserved32[13]; + + u32 apu2ppu_mb_offset; + u32 apu2ppu_irq; + u32 apu2ppu_irq_ack; + u32 reserved33[13]; + + u32 hpu2ppu_mb_offset; + u32 hpu2ppu_irq; + u32 hpu2ppu_irq_ack; + u32 reserved34[13]; + + u32 epu2ppu_mb_offset; + u32 epu2ppu_irq; + u32 epu2ppu_irq_ack; + u32 reserved35[13]; + u32 reserved36[8]; + + /* Fields for EPU: */ + + u32 epu_state; + u32 reserved41[7]; + u32 cpu2epu_mb_offset; + u32 cpu2epu_irq; + u32 cpu2epu_irq_ack; + u32 reserved42[13]; + + u32 apu2epu_mb_offset; + u32 apu2epu_irq; + u32 apu2epu_irq_ack; + u32 reserved43[13]; + + u32 hpu2epu_mb_offset; + u32 hpu2epu_irq; + u32 hpu2epu_irq_ack; + u32 reserved44[13]; + + u32 ppu2epu_mb_offset; + u32 ppu2epu_irq; + u32 ppu2epu_irq_ack; + u32 reserved45[13]; + u32 reserved46[8]; + + u32 semaphores[8]; /* Semaphores */ + + u32 reserved50[32]; /* Reserved for future use */ + + struct cx18_mailbox apu2cpu_mb; + struct cx18_mailbox hpu2cpu_mb; + struct cx18_mailbox ppu2cpu_mb; + struct cx18_mailbox epu2cpu_mb; + + struct cx18_mailbox cpu2apu_mb; + struct cx18_mailbox hpu2apu_mb; + struct cx18_mailbox ppu2apu_mb; + struct cx18_mailbox epu2apu_mb; + + struct cx18_mailbox cpu2hpu_mb; + struct cx18_mailbox apu2hpu_mb; + struct cx18_mailbox ppu2hpu_mb; + struct cx18_mailbox epu2hpu_mb; + + struct cx18_mailbox cpu2ppu_mb; + struct cx18_mailbox apu2ppu_mb; + struct cx18_mailbox hpu2ppu_mb; + struct cx18_mailbox epu2ppu_mb; + + struct cx18_mailbox cpu2epu_mb; + struct cx18_mailbox apu2epu_mb; + struct cx18_mailbox hpu2epu_mb; + struct cx18_mailbox ppu2epu_mb; + + struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2]; + struct cx18_mdl cpu_mdl[1]; +}; + +void cx18_init_scb(struct cx18 *cx); + +#endif diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c new file mode 100644 index 000000000000..afb141b2027a --- /dev/null +++ b/drivers/media/video/cx18/cx18-streams.c @@ -0,0 +1,566 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-ioctl.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "cx18-scb.h" +#include "cx18-av-core.h" +#include "cx18-dvb.h" + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +static struct file_operations cx18_v4l2_enc_fops = { + .owner = THIS_MODULE, + .read = cx18_v4l2_read, + .open = cx18_v4l2_open, + .ioctl = cx18_v4l2_ioctl, + .release = cx18_v4l2_close, + .poll = cx18_v4l2_enc_poll, +}; + +/* offset from 0 to register ts v4l2 minors on */ +#define CX18_V4L2_ENC_TS_OFFSET 16 +/* offset from 0 to register pcm v4l2 minors on */ +#define CX18_V4L2_ENC_PCM_OFFSET 24 +/* offset from 0 to register yuv v4l2 minors on */ +#define CX18_V4L2_ENC_YUV_OFFSET 32 + +static struct { + const char *name; + int vfl_type; + int minor_offset; + int dma; + enum v4l2_buf_type buf_type; + struct file_operations *fops; +} cx18_stream_info[] = { + { /* CX18_ENC_STREAM_TYPE_MPG */ + "encoder MPEG", + VFL_TYPE_GRABBER, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_TS */ + "TS", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_PCM */ + "encoder PCM audio", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_IDX */ + "encoder IDX", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, + PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE, + &cx18_v4l2_enc_fops + }, +}; + +static void cx18_stream_init(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + struct video_device *dev = s->v4l2dev; + u32 max_size = cx->options.megabytes[type] * 1024 * 1024; + + /* we need to keep v4l2dev, so restore it afterwards */ + memset(s, 0, sizeof(*s)); + s->v4l2dev = dev; + + /* initialize cx18_stream fields */ + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + s->handle = 0xffffffff; + + s->dma = cx18_stream_info[type].dma; + s->buf_size = cx->stream_buf_size[type]; + if (s->buf_size) + s->buffers = max_size / s->buf_size; + if (s->buffers > 63) { + /* Each stream has a maximum of 63 buffers, + ensure we do not exceed that. */ + s->buffers = 63; + s->buf_size = (max_size / s->buffers) & ~0xfff; + } + spin_lock_init(&s->qlock); + init_waitqueue_head(&s->waitq); + s->id = -1; + cx18_queue_init(&s->q_free); + cx18_queue_init(&s->q_full); + cx18_queue_init(&s->q_io); +} + +static int cx18_prep_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + u32 cap = cx->v4l2_cap; + int minor_offset = cx18_stream_info[type].minor_offset; + int minor; + + /* These four fields are always initialized. If v4l2dev == NULL, then + this stream is not in use. In that case no other fields but these + four can be used. */ + s->v4l2dev = NULL; + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + + /* Check whether the radio is supported */ + if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) + return 0; + + /* Check whether VBI is supported */ + if (type == CX18_ENC_STREAM_TYPE_VBI && + !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) + return 0; + + /* card number + user defined offset + device offset */ + minor = cx->num + cx18_first_minor + minor_offset; + + /* User explicitly selected 0 buffers for these streams, so don't + create them. */ + if (cx18_stream_info[type].dma != PCI_DMA_NONE && + cx->options.megabytes[type] == 0) { + CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); + return 0; + } + + cx18_stream_init(cx, type); + + if (minor_offset == -1) + return 0; + + /* allocate and initialize the v4l2 video device structure */ + s->v4l2dev = video_device_alloc(); + if (s->v4l2dev == NULL) { + CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", + s->name); + return -ENOMEM; + } + + s->v4l2dev->type = + VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | + VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; + snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s", + cx->num, s->name); + + s->v4l2dev->minor = minor; + s->v4l2dev->dev = &cx->dev->dev; + s->v4l2dev->fops = cx18_stream_info[type].fops; + s->v4l2dev->release = video_device_release; + + return 0; +} + +/* Initialize v4l2 variables and register v4l2 devices */ +int cx18_streams_setup(struct cx18 *cx) +{ + int type; + + /* Setup V4L2 Devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + /* Prepare device */ + if (cx18_prep_dev(cx, type)) + break; + + /* Allocate Stream */ + if (cx18_stream_alloc(&cx->streams[type])) + break; + } + if (type == CX18_MAX_STREAMS) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx); + return -ENOMEM; +} + +static int cx18_reg_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + int vfl_type = cx18_stream_info[type].vfl_type; + int minor; + + /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? + * We need a VFL_TYPE_TS defined. + */ + if (strcmp("TS", s->name) == 0) { + /* just return if no DVB is supported */ + if ((cx->card->hw_all & CX18_HW_DVB) == 0) + return 0; + if (cx18_dvb_register(s) < 0) { + CX18_ERR("DVB failed to register\n"); + return -EINVAL; + } + } + + if (s->v4l2dev == NULL) + return 0; + + minor = s->v4l2dev->minor; + + /* Register device. First try the desired minor, then any free one. */ + if (video_register_device(s->v4l2dev, vfl_type, minor) && + video_register_device(s->v4l2dev, vfl_type, -1)) { + CX18_ERR("Couldn't register v4l2 device for %s minor %d\n", + s->name, minor); + video_device_release(s->v4l2dev); + s->v4l2dev = NULL; + return -ENOMEM; + } + minor = s->v4l2dev->minor; + + switch (vfl_type) { + case VFL_TYPE_GRABBER: + CX18_INFO("Registered device video%d for %s (%d MB)\n", + minor, s->name, cx->options.megabytes[type]); + break; + + case VFL_TYPE_RADIO: + CX18_INFO("Registered device radio%d for %s\n", + minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); + break; + + case VFL_TYPE_VBI: + if (cx->options.megabytes[type]) + CX18_INFO("Registered device vbi%d for %s (%d MB)\n", + minor - MINOR_VFL_TYPE_VBI_MIN, + s->name, cx->options.megabytes[type]); + else + CX18_INFO("Registered device vbi%d for %s\n", + minor - MINOR_VFL_TYPE_VBI_MIN, s->name); + break; + } + + return 0; +} + +/* Register v4l2 devices */ +int cx18_streams_register(struct cx18 *cx) +{ + int type; + int err = 0; + + /* Register V4L2 devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) + err |= cx18_reg_dev(cx, type); + + if (err == 0) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx); + return -ENOMEM; +} + +/* Unregister v4l2 devices */ +void cx18_streams_cleanup(struct cx18 *cx) +{ + struct video_device *vdev; + int type; + + /* Teardown all streams */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + if (cx->streams[type].dvb.enabled) + cx18_dvb_unregister(&cx->streams[type]); + + vdev = cx->streams[type].v4l2dev; + + cx->streams[type].v4l2dev = NULL; + if (vdev == NULL) + continue; + + cx18_stream_free(&cx->streams[type]); + + /* Unregister device */ + video_unregister_device(vdev); + } +} + +static void cx18_vbi_setup(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int raw = cx->vbi.sliced_in->service_set == 0; + u32 data[CX2341X_MBOX_MAX_DATA]; + int lines; + + if (cx->is_60hz) { + cx->vbi.count = 12; + cx->vbi.start[0] = 10; + cx->vbi.start[1] = 273; + } else { /* PAL/SECAM */ + cx->vbi.count = 18; + cx->vbi.start[0] = 6; + cx->vbi.start[1] = 318; + } + + /* setup VBI registers */ + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + + /* determine number of lines and total number of VBI bytes. + A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 + The '- 1' byte is probably an unused U or V byte. Or something... + A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal + header, 42 data bytes + checksum (to be confirmed) */ + if (raw) { + lines = cx->vbi.count * 2; + } else { + lines = cx->is_60hz ? 24 : 38; + if (cx->is_60hz) + lines += 2; + } + + cx->vbi.enc_size = lines * + (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + + data[0] = s->handle; + /* Lines per field */ + data[1] = (lines / 2) | ((lines / 2) << 16); + /* bytes per line */ + data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + /* Every X number of frames a VBI interrupt arrives + (frames as in 25 or 30 fps) */ + data[3] = 1; + /* Setup VBI for the cx25840 digitizer */ + if (raw) { + data[4] = 0x20602060; + data[5] = 0x30703070; + } else { + data[4] = 0xB0F0B0F0; + data[5] = 0xA0E0A0E0; + } + + CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", + data[0], data[1], data[2], data[3], data[4], data[5]); + + if (s->type == CX18_ENC_STREAM_TYPE_VBI) + cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); +} + +int cx18_start_v4l2_encode_stream(struct cx18_stream *s) +{ + u32 data[MAX_MB_ARGUMENTS]; + struct cx18 *cx = s->cx; + struct list_head *p; + int ts = 0; + int captype = 0; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + return -EINVAL; + + CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); + + switch (s->type) { + case CX18_ENC_STREAM_TYPE_MPG: + captype = CAPTURE_CHANNEL_TYPE_MPEG; + cx->mpg_data_received = cx->vbi_data_inserted = 0; + cx->dualwatch_jiffies = jiffies; + cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300; + cx->search_pack_header = 0; + break; + + case CX18_ENC_STREAM_TYPE_TS: + captype = CAPTURE_CHANNEL_TYPE_TS; + ts = 1; + break; + case CX18_ENC_STREAM_TYPE_YUV: + captype = CAPTURE_CHANNEL_TYPE_YUV; + break; + case CX18_ENC_STREAM_TYPE_PCM: + captype = CAPTURE_CHANNEL_TYPE_PCM; + break; + case CX18_ENC_STREAM_TYPE_VBI: + captype = cx->vbi.sliced_in->service_set ? + CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI; + cx->vbi.frame = 0; + cx->vbi.inserted_frame = 0; + memset(cx->vbi.sliced_mpeg_size, + 0, sizeof(cx->vbi.sliced_mpeg_size)); + break; + default: + return -EINVAL; + } + s->buffers_stolen = 0; + + /* mute/unmute video */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)); + + /* Clear Streamoff flags in case left from last capture */ + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); + s->handle = data[0]; + cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); + + if (atomic_read(&cx->capturing) == 0 && !ts) { + /* Stuff from Windows, we don't know what it is */ + cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); + + cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, + s->handle, cx->digitizer, cx->digitizer); + + /* Setup VBI */ + if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) + cx18_vbi_setup(s); + + /* assign program index info. + Mask 7: select I/P/B, Num_req: 400 max */ + cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0); + + /* Setup API for Stream */ + cx2341x_update(cx, cx18_api_func, NULL, &cx->params); + } + + if (atomic_read(&cx->capturing) == 0) { + clear_bit(CX18_F_I_EOS, &cx->i_flags); + write_reg(7, CX18_DSP0_INTERRUPT_MASK); + } + + cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, + (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, + (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); + + list_for_each(p, &s->q_free.list) { + struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); + + writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); + writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1, + buf->id, s->buf_size); + } + /* begin_capture */ + if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { + CX18_DEBUG_WARN("Error starting capture!\n"); + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + return -EINVAL; + } + + /* you're live! sit back and await interrupts :) */ + atomic_inc(&cx->capturing); + return 0; +} + +void cx18_stop_all_captures(struct cx18 *cx) +{ + int i; + + for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + continue; + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) + cx18_stop_v4l2_encode_stream(s, 0); + } +} + +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) +{ + struct cx18 *cx = s->cx; + unsigned long then; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + return -EINVAL; + + /* This function assumes that you are allowed to stop the capture + and that we are actually capturing */ + + CX18_DEBUG_INFO("Stop Capture\n"); + + if (atomic_read(&cx->capturing) == 0) + return 0; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); + else + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + + then = jiffies; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { + CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); + } + + atomic_dec(&cx->capturing); + + /* Clear capture and no-read bits */ + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + s->handle = 0xffffffff; + + if (atomic_read(&cx->capturing) > 0) + return 0; + + write_reg(5, CX18_DSP0_INTERRUPT_MASK); + wake_up(&s->waitq); + + return 0; +} + +u32 cx18_find_handle(struct cx18 *cx) +{ + int i; + + /* find first available handle to be used for global settings */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev && s->handle) + return s->handle; + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h new file mode 100644 index 000000000000..8c7ba7d2fa79 --- /dev/null +++ b/drivers/media/video/cx18/cx18-streams.h @@ -0,0 +1,33 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +u32 cx18_find_handle(struct cx18 *cx); +int cx18_streams_setup(struct cx18 *cx); +int cx18_streams_register(struct cx18 *cx); +void cx18_streams_cleanup(struct cx18 *cx); + +/* Capture related */ +int cx18_start_v4l2_encode_stream(struct cx18_stream *s); +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); + +void cx18_stop_all_captures(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c new file mode 100644 index 000000000000..22e76ee3f447 --- /dev/null +++ b/drivers/media/video/cx18/cx18-vbi.c @@ -0,0 +1,208 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-vbi.h" +#include "cx18-ioctl.h" +#include "cx18-queue.h" +#include "cx18-av-core.h" + +static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) +{ + int line = 0; + int i; + u32 linemask[2] = { 0, 0 }; + unsigned short size; + static const u8 mpeg_hdr_data[] = { + 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, + 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, + 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff + }; + const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ + int idx = cx->vbi.frame % CX18_VBI_FRAMES; + u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0]; + + for (i = 0; i < lines; i++) { + struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i; + int f, l; + + if (sdata->id == 0) + continue; + + l = sdata->line - 6; + f = sdata->field; + if (f) + l += 18; + if (l < 32) + linemask[0] |= (1 << l); + else + linemask[1] |= (1 << (l - 32)); + dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id); + memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42); + line++; + } + memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); + if (line == 36) { + /* All lines are used, so there is no space for the linemask + (the max size of the VBI data is 36 * 43 + 4 bytes). + So in this case we use the magic number 'ITV0'. */ + memcpy(dst + sd, "ITV0", 4); + memcpy(dst + sd + 4, dst + sd + 12, line * 43); + size = 4 + ((43 * line + 3) & ~3); + } else { + memcpy(dst + sd, "cx0", 4); + memcpy(dst + sd + 4, &linemask[0], 8); + size = 12 + ((43 * line + 3) & ~3); + } + dst[4+16] = (size + 10) >> 8; + dst[5+16] = (size + 10) & 0xff; + dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); + dst[10+16] = (pts_stamp >> 22) & 0xff; + dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); + dst[12+16] = (pts_stamp >> 7) & 0xff; + dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); + cx->vbi.sliced_mpeg_size[idx] = sd + size; +} + +/* Compress raw VBI format, removes leading SAV codes and surplus space + after the field. + Returns new compressed size. */ +static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size) +{ + u32 line_size = cx->vbi.raw_decoder_line_size; + u32 lines = cx->vbi.count; + u8 sav1 = cx->vbi.raw_decoder_sav_odd_field; + u8 sav2 = cx->vbi.raw_decoder_sav_even_field; + u8 *q = buf; + u8 *p; + int i; + + for (i = 0; i < lines; i++) { + p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || + (p[3] != sav1 && p[3] != sav2)) + break; + memcpy(q, p + 4, line_size - 4); + q += line_size - 4; + } + return lines * (line_size - 4); +} + + +/* Compressed VBI format, all found sliced blocks put next to one another + Returns new compressed size */ +static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf, + u32 size, u8 sav) +{ + u32 line_size = cx->vbi.sliced_decoder_line_size; + struct v4l2_decode_vbi_line vbi; + int i; + + /* find the first valid line */ + for (i = 0; i < size; i++, buf++) { + if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) + break; + } + + size -= i; + if (size < line_size) + return line; + for (i = 0; i < size / line_size; i++) { + u8 *p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) + continue; + vbi.p = p + 4; + cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi); + if (vbi.type) { + cx->vbi.sliced_data[line].id = vbi.type; + cx->vbi.sliced_data[line].field = vbi.is_second_field; + cx->vbi.sliced_data[line].line = vbi.line; + memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42); + line++; + } + } + return line; +} + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, + u64 pts_stamp, int streamtype) +{ + u8 *p = (u8 *) buf->buf; + u32 size = buf->bytesused; + int lines; + + if (streamtype != CX18_ENC_STREAM_TYPE_VBI) + return; + + /* Raw VBI data */ + if (cx->vbi.sliced_in->service_set == 0) { + u8 type; + + cx18_buf_swap(buf); + + type = p[3]; + + size = buf->bytesused = compress_raw_buf(cx, p, size); + + /* second field of the frame? */ + if (type == cx->vbi.raw_decoder_sav_even_field) { + /* Dirty hack needed for backwards + compatibility of old VBI software. */ + p += size - 4; + memcpy(p, &cx->vbi.frame, 4); + cx->vbi.frame++; + } + return; + } + + /* Sliced VBI data with data insertion */ + cx18_buf_swap(buf); + + /* first field */ + lines = compress_sliced_buf(cx, 0, p, size / 2, + cx->vbi.sliced_decoder_sav_odd_field); + /* second field */ + /* experimentation shows that the second half does not always + begin at the exact address. So start a bit earlier + (hence 32). */ + lines = compress_sliced_buf(cx, lines, p + size / 2 - 32, + size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field); + /* always return at least one empty line */ + if (lines == 0) { + cx->vbi.sliced_data[0].id = 0; + cx->vbi.sliced_data[0].line = 0; + cx->vbi.sliced_data[0].field = 0; + lines = 1; + } + buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]); + memcpy(p, &cx->vbi.sliced_data[0], size); + + if (cx->vbi.insert_mpeg) + copy_vbi_data(cx, lines, pts_stamp); + cx->vbi.frame++; +} diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h new file mode 100644 index 000000000000..c56ff7d28f20 --- /dev/null +++ b/drivers/media/video/cx18/cx18-vbi.h @@ -0,0 +1,26 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, + u64 pts_stamp, int streamtype); +int cx18_used_line(struct cx18 *cx, int line, int field); diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h new file mode 100644 index 000000000000..d5c7a6f968dd --- /dev/null +++ b/drivers/media/video/cx18/cx18-version.h @@ -0,0 +1,34 @@ +/* + * cx18 driver version information + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#ifndef CX18_VERSION_H +#define CX18_VERSION_H + +#define CX18_DRIVER_NAME "cx18" +#define CX18_DRIVER_VERSION_MAJOR 1 +#define CX18_DRIVER_VERSION_MINOR 0 +#define CX18_DRIVER_VERSION_PATCHLEVEL 0 + +#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) +#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ + CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) + +#endif diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c new file mode 100644 index 000000000000..2e5c41939330 --- /dev/null +++ b/drivers/media/video/cx18/cx18-video.c @@ -0,0 +1,45 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-video.h" +#include "cx18-av-core.h" +#include "cx18-cards.h" + +void cx18_video_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + int inp = cx->active_input; + u32 type; + + route.input = cx->card->video_inputs[inp].video_input; + route.output = 0; + cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route); + + type = cx->card->video_inputs[inp].video_type; + + if (type == CX18_CARD_INPUT_VID_TUNER) + route.input = 0; /* Tuner */ + else if (type < CX18_CARD_INPUT_COMPOSITE1) + route.input = 2; /* S-Video */ + else + route.input = 1; /* Composite */ +} diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h new file mode 100644 index 000000000000..529006a06e5c --- /dev/null +++ b/drivers/media/video/cx18/cx18-video.h @@ -0,0 +1,22 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +void cx18_video_set_io(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h new file mode 100644 index 000000000000..33f78da9dba8 --- /dev/null +++ b/drivers/media/video/cx18/cx23418.h @@ -0,0 +1,458 @@ +/* + * cx18 header containing common defines. + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#ifndef CX23418_H +#define CX23418_H + +#include <media/cx2341x.h> + +#define MGR_CMD_MASK 0x40000000 +/* The MSB of the command code indicates that this is the completion of a + command */ +#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000) + +/* Description: This command creates a new instance of a certain task + IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is + the processor on which the task YYY will be created + OUT[0] - Task handle. This handle is passed along with commands to + dispatch to the right instance of the task + ReturnCode - One of the ERR_SYS_... */ +#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001) + +/* Description: This command destroys an instance of a task + IN[0] - Task handle. Hanlde of the task to destroy + ReturnCode - One of the ERR_SYS_... */ +#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002) + +/* All commands for CPU have the following mask set */ +#define CPU_CMD_MASK 0x20000000 +#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) +#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) +#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) + +#define EPU_CMD_MASK 0x02000000 +#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) +#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) + +/* Description: This command indicates that a Memory Descriptor List has been + filled with the requested channel type + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the MDL_ACK from the beginning of the local DDR. + IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1] + ReturnCode - One of the ERR_DE_... */ +#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001) + +/* Something interesting happened + IN[0] - A value to log + IN[1] - An offset of a string in the MiniMe memory; + 0/zero/NULL means "I have nothing to say" */ +#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) + +/* Description: This command starts streaming with the set channel type + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002) + +/* Description: This command stops streaming with the set channel type + IN[0] - Task handle. Handle of the task to stop + IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only) + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003) + +/* Description: This command pauses streaming with the set channel type + IN[0] - Task handle. Handle of the task to pause + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007) + +/* Description: This command resumes streaming with the set channel type + IN[0] - Task handle. Handle of the task to resume + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008) + +#define CAPTURE_CHANNEL_TYPE_NONE 0 +#define CAPTURE_CHANNEL_TYPE_MPEG 1 +#define CAPTURE_CHANNEL_TYPE_INDEX 2 +#define CAPTURE_CHANNEL_TYPE_YUV 3 +#define CAPTURE_CHANNEL_TYPE_PCM 4 +#define CAPTURE_CHANNEL_TYPE_VBI 5 +#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6 +#define CAPTURE_CHANNEL_TYPE_TS 7 +#define CAPTURE_CHANNEL_TYPE_MAX 15 + +/* Description: This command sets the channel type. This can only be done + when stopped. + IN[0] - Task handle. Handle of the task to start + IN[1] - Channel Type. See Below. + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - type + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012) + +/* Description: Set video input resolution and frame rate + IN[0] - task handle + IN[1] - reserved + IN[2] - reserved + IN[3] - reserved + IN[4] - reserved + IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004) + +/* Description: Set video frame rate + IN[0] - task handle. Handle of the task to start + IN[1] - video bit rate mode + IN[2] - video average rate + IN[3] - video peak rate + IN[4] - system mux rate + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005) + +/* Description: Set video output resolution + IN[0] - task handle + IN[1] - horizontal size + IN[2] - vertical size + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006) + +/* Description: This command set filter parameters + IN[0] - Task handle. Handle of the task + IN[1] - type, 0 - temporal, 1 - spatial, 2 - median + IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic + median: 0 = disable, 1 = horizontal, 2 = vertical, + 3 = horizontal/vertical, 4 = diagonal + IN[3] - strength, temporal 0 - 31, spatial 0 - 15 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009) + +/* Description: This command set spatial filter type + IN[0] - Task handle. + IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, + 3 = 2D H/V separable, 4 = 2D symmetric non-separable + IN[2] - chroma type: 0 - diable, 1 = 1D horizontal + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) + +/* Description: This command set coring levels for median filter + IN[0] - Task handle. + IN[1] - luma_high + IN[2] - luma_low + IN[3] - chroma_high + IN[4] - chroma_low + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E) + +/* Description: This command set the picture type mask for index file + IN[0] - 0 = disable index file output + 1 = output I picture + 2 = P picture + 4 = B picture + other = illegal */ +#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010) + +/* Description: Set audio parameters + IN[0] - task handle. Handle of the task to start + IN[1] - audio parameter + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011) + +/* Description: Set video mute + IN[0] - task handle. Handle of the task to start + IN[1] - bit31-24: muteYvalue + bit23-16: muteUvalue + bit15-8: muteVvalue + bit0: 1:mute, 0: unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013) + +/* Description: Set audio mute + IN[0] - task handle. Handle of the task to start + IN[1] - mute/unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - subType + SET_INITIAL_SCR 1 + SET_QUALITY_MODE 2 + SET_VIM_PROTECT_MODE 3 + SET_PTS_CORRECTION 4 + SET_USB_FLUSH_MODE 5 + SET_MERAQPAR_ENABLE 6 + SET_NAV_PACK_INSERTION 7 + SET_SCENE_CHANGE_ENABLE 8 + IN[2] - parameter 1 + IN[3] - parameter 2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015) + +/* Description: Set raw VBI parameters + IN[0] - Task handle + IN[1] - No. of input lines per field: + bit[15:0]: field 1, + bit[31:16]: field 2 + IN[2] - No. of input bytes per line + IN[3] - No. of output frames per transfer + IN[4] - start code + IN[5] - stop code + ReturnCode */ +#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016) + +/* Description: Set capture line No. + IN[0] - task handle. Handle of the task to start + IN[1] - height1 + IN[2] - height2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017) + +/* Description: Set copyright + IN[0] - task handle. Handle of the task to start + IN[1] - copyright + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018) + +/* Description: Set audio PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019) + +/* Description: Set video PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A) + +/* Description: Set Vertical Crop Line + IN[0] - task handle. Handle of the task to start + IN[1] - Line + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B) + +/* Description: Set COP structure + IN[0] - task handle. Handle of the task to start + IN[1] - M + IN[2] - N + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C) + +/* Description: Set Scene Change Detection + IN[0] - task handle. Handle of the task to start + IN[1] - scene change + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D) + +/* Description: Set Aspect Ratio + IN[0] - task handle. Handle of the task to start + IN[1] - AspectRatio + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E) + +/* Description: Set Skip Input Frame + IN[0] - task handle. Handle of the task to start + IN[1] - skip input frames + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F) + +/* Description: Set sliced VBI parameters - + Note This API will only apply to MPEG and Sliced VBI Channels + IN[0] - Task handle + IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext + IN[2] - start / stop line + bit[15:0] start line number + bit[31:16] stop line number + IN[3] - number of output frames per interrupt + IN[4] - VBI insertion mode + bit 0: output user data, 1 - enable + bit 1: output private stream, 1 - enable + bit 2: mux option, 0 - in GOP, 1 - in picture + bit[7:0] private stream ID + IN[5] - insertion period while mux option is in picture + ReturnCode - VBI data offset */ +#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020) + +/* Description: Set the user data place holder + IN[0] - type of data (0 for user) + IN[1] - Stuffing period + IN[2] - ID data size in word (less than 10) + IN[3] - Pointer to ID buffer */ +#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021) + + +/* Description: + In[0] Task Handle + return parameter: + Out[0] Reserved + Out[1] Video PTS bit[32:2] of last output video frame. + Out[2] Video PTS bit[ 1:0] of last output video frame. + Out[3] Hardware Video PTS counter bit[31:0], + these bits get incremented on every 90kHz clock tick. + Out[4] Hardware Video PTS counter bit32, + these bits get incremented on every 90kHz clock tick. + ReturnCode */ +#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) + +/* Below is the list of commands related to the data exchange */ +#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) + +/* Description: This command provides the physical base address of the local + DDR as viewed by EPU + IN[0] - Physical offset where EPU has the local DDR mapped + ReturnCode - One of the ERR_DE_... */ +#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001) + +/* Description: This command provides the offsets in the device memory where + the 2 cx18_mdl_ack blocks reside + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the first cx18_mdl_ack from the beginning of the + local DDR. + IN[2] - Offset of the second cx18_mdl_ack from the beginning of the + local DDR. + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002) + +/* Description: This command provides the offset to a Memory Descriptor List + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the MDL from the beginning of the local DDR. + IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1] + IN[3] - Buffer ID + IN[4] - Total buffer length + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005) + +/* Description: This command requests return of all current Memory + Descriptor Lists to the driver + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */ + +/* Description: This command signals the cpu that the dat buffer has been + consumed and ready for re-use. + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the data block from the beginning of the local DDR. + IN[2] - Number of bytes in the data block + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */ + +/* No Error / Success */ +#define CNXT_OK 0x000000 + +/* Received unknown command */ +#define CXERR_UNK_CMD 0x000001 + +/* First parameter in the command is invalid */ +#define CXERR_INVALID_PARAM1 0x000002 + +/* Second parameter in the command is invalid */ +#define CXERR_INVALID_PARAM2 0x000003 + +/* Device interface is not open/found */ +#define CXERR_DEV_NOT_FOUND 0x000004 + +/* Requested function is not implemented/available */ +#define CXERR_NOTSUPPORTED 0x000005 + +/* Invalid pointer is provided */ +#define CXERR_BADPTR 0x000006 + +/* Unable to allocate memory */ +#define CXERR_NOMEM 0x000007 + +/* Object/Link not found */ +#define CXERR_LINK 0x000008 + +/* Device busy, command cannot be executed */ +#define CXERR_BUSY 0x000009 + +/* File/device/handle is not open. */ +#define CXERR_NOT_OPEN 0x00000A + +/* Value is out of range */ +#define CXERR_OUTOFRANGE 0x00000B + +/* Buffer overflow */ +#define CXERR_OVERFLOW 0x00000C + +/* Version mismatch */ +#define CXERR_BADVER 0x00000D + +/* Operation timed out */ +#define CXERR_TIMEOUT 0x00000E + +/* Operation aborted */ +#define CXERR_ABORT 0x00000F + +/* Specified I2C device not found for read/write */ +#define CXERR_I2CDEV_NOTFOUND 0x000010 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_XFERERR 0x000011 + +/* Chanel changing component not ready */ +#define CXERR_CHANNELNOTREADY 0x000012 + +/* PPU (Presensation/Decoder) mail box is corrupted */ +#define CXERR_PPU_MB_CORRUPT 0x000013 + +/* CPU (Capture/Encoder) mail box is corrupted */ +#define CXERR_CPU_MB_CORRUPT 0x000014 + +/* APU (Audio) mail box is corrupted */ +#define CXERR_APU_MB_CORRUPT 0x000015 + +/* Unable to open file for reading */ +#define CXERR_FILE_OPEN_READ 0x000016 + +/* Unable to open file for writing */ +#define CXERR_FILE_OPEN_WRITE 0x000017 + +/* Unable to find the I2C section specified */ +#define CXERR_I2C_BADSECTION 0x000018 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_DATALOW 0x000019 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_CLOCKLOW 0x00001A + +/* No Interrupt received from HW (for I2C access) */ +#define CXERR_NO_HW_I2C_INTR 0x00001B + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NOT_READY 0x00001C + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NO_ACK 0x00001D + +/* The are no buffers ready. Try again soon! */ +#define CXERR_NODATA_AGAIN 0x00001E + +/* The stream is stopping. Function not alllowed now! */ +#define CXERR_STOPPING_STATUS 0x00001F + +/* Trying to access hardware when the power is turned OFF */ +#define CXERR_DEVPOWER_OFF 0x000020 + +#endif /* CX23418_H */ diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ca5fbce3a909..cadf936c3673 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,19 +4,19 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_DVB select VIDEO_CX25840 - select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE - select TUNER_XC2028 if !DVB_FE_CUSTOMIZE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index d7b0721af062..29c23b44c13c 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -3,6 +3,7 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx2 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 7fde678b2c4a..88823810497c 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1209,7 +1209,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static int cx25840_probe(struct i2c_client *client) +static int cx25840_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct cx25840_state *state; u32 id; diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 27635cdcbaf2..b0d7d6a7a4cc 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -5,7 +5,7 @@ config VIDEO_CX88 select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO @@ -57,7 +57,7 @@ config VIDEO_CX88_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB/ATSC cards based on the diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 532cee35eb3c..6ec30f242578 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 2b6b283cda15..aeba26dc0a37 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -57,6 +57,9 @@ MODULE_PARM_DESC(latency,"pci latency timer"); /* ------------------------------------------------------------------ */ /* board config info */ +/* If radio_type !=UNSET, radio_addr should be specified + */ + static const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", @@ -2446,25 +2449,31 @@ EXPORT_SYMBOL_GPL(cx88_setup_xc3028); static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | + T_ANALOG_TV | + T_DIGITAL_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); if (0 == core->i2c_rc) { core->i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); + tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); } switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) - hauppauge_eeprom(core,eeprom+8); + hauppauge_eeprom(core, eeprom+8); break; case CX88_BOARD_GDI: if (0 == core->i2c_rc) - gdi_eeprom(core,eeprom); + gdi_eeprom(core, eeprom); break; case CX88_BOARD_WINFAST2000XP_EXPERT: if (0 == core->i2c_rc) - leadtek_eeprom(core,eeprom); + leadtek_eeprom(core, eeprom); break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: @@ -2474,7 +2483,7 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR1300: if (0 == core->i2c_rc) - hauppauge_eeprom(core,eeprom); + hauppauge_eeprom(core, eeprom); break; case CX88_BOARD_KWORLD_DVBS_100: cx_write(MO_GP0_IO, 0x000007f8); @@ -2555,6 +2564,35 @@ static void cx88_card_setup(struct cx88_core *core) cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); } + } /*end switch() */ + + + /* Setup tuners */ + if ((core->board.radio_type != UNSET)) { + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if (core->board.tuner_type != TUNER_ABSENT) { + tun_setup.mode_mask = mode_mask; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + + cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg); } if (core->board.tuner_type == TUNER_XC2028) { @@ -2572,6 +2610,7 @@ static void cx88_card_setup(struct cx88_core *core) ctl.fname); cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg); } + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); } /* ------------------------------------------------------------------ */ @@ -2710,7 +2749,6 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (TUNER_ABSENT != core->board.tuner_type) request_module("tuner"); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); cx88_card_setup(core); cx88_ir_init(core, pci); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c6b44732a082..cb6a096069c7 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -99,42 +99,11 @@ static int cx8800_bit_getsda(void *data) static int attach_inform(struct i2c_client *client) { - struct tuner_setup tun_setup; struct cx88_core *core = i2c_get_adapdata(client->adapter); dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); - if (!client->driver->command) - return 0; - - if (core->board.radio_type != UNSET) { - if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - if (core->board.tuner_type != UNSET) { - if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - - if (core->board.tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &core->board.tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); - } return 0; } diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 9caffed2b6b8..c7c2896bbd8b 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,7 +1,7 @@ config VIDEO_EM28XX tristate "Empia EM28xx USB video capture support" depends on VIDEO_DEV && I2C && INPUT - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_VMALLOC diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 3d1c3cc337fe..8137a8c94bfc 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index b6171702c4d0..eec115bf9517 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -4,7 +4,7 @@ config VIDEO_IVTV select I2C_ALGOBIT select FW_LOADER select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_CX25840 diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index a0389014fa88..26ce0d6eaee1 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index e908649ea37c..4fb8faefe2ce 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -40,6 +40,8 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM) + /* usual i2c tuner addresses to probe */ static struct ivtv_card_tuner_i2c ivtv_i2c_std = { .radio = { I2C_CLIENT_END }, @@ -298,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = { .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { /* The PAL tuner is confirmed */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, @@ -339,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = { .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, @@ -375,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, @@ -416,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = { on the country/region setting of the user to decide which tuner is available. */ .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FM1236_MK3 }, { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 }, @@ -490,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020 }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, .i2c = &ivtv_i2c_std, @@ -521,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = { { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, .i2c = &ivtv_i2c_std, @@ -565,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, @@ -597,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -627,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -667,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, .i2c = &ivtv_i2c_std, @@ -704,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, .i2c = &ivtv_i2c_std, @@ -739,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, .tuners = { /* This card has a Philips FQ1216ME MK3 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, .i2c = &ivtv_i2c_std, @@ -778,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Philips FQ1216ME MK5 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, .i2c = &ivtv_i2c_std, @@ -856,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020}, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, .i2c = &ivtv_i2c_std, @@ -875,6 +877,7 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, .name = "Yuan PG600-2, GotView PCI DVD Lite", + .comment = "only Composite and S-Video inputs are supported, not the tuner\n", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, @@ -921,6 +924,7 @@ static const struct ivtv_card ivtv_card_club3d = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ + .xceive_pin = 12, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, @@ -944,15 +948,22 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, }, .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, - .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + /* enable line-in */ + .gpio_init = { .direction = 0xe400, .initial_value = 0x4400 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, .pci_list = ivtv_pci_avertv_mce116, .i2c = &ivtv_i2c_std, }; @@ -990,7 +1001,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Partsnic PTI-5NF05 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N }, }, .pci_list = ivtv_pci_aver_pvr150, .i2c = &ivtv_i2c_radio, @@ -1058,12 +1069,48 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_asus_falcon2, .i2c = &ivtv_i2c_std, }; +/* ------------------------------------------------------------------------- */ + +/* AVerMedia M104 miniPCI card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_m104 = { + .type = IVTV_CARD_AVER_M104, + .name = "AVerMedia M104", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/ + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + /* enable line-in + reset tuner */ + .gpio_init = { .direction = 0xe400, .initial_value = 0x4000 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_aver_m104, + .i2c = &ivtv_i2c_std, +}; + static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, &ivtv_card_pvr350, @@ -1089,6 +1136,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_asus_falcon2, &ivtv_card_aver_pvr150, &ivtv_card_aver_ezmaker, + &ivtv_card_aver_m104, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ @@ -1120,7 +1168,8 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) if (index >= itv->nof_inputs) return -EINVAL; input->index = index; - strcpy(input->name, input_strs[card_input->video_type - 1]); + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); input->audioset = (1 << itv->nof_audio_inputs) - 1; @@ -1137,7 +1186,7 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) if (index >= itv->card->nof_outputs) return -EINVAL; output->index = index; - strcpy(output->name, card_output->name); + strlcpy(output->name, card_output->name, sizeof(output->name)); output->type = V4L2_OUTPUT_TYPE_ANALOG; output->audioset = 1; output->std = V4L2_STD_ALL; @@ -1156,7 +1205,8 @@ int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) memset(audio, 0, sizeof(*audio)); if (index >= itv->nof_audio_inputs) return -EINVAL; - strcpy(audio->name, input_strs[aud_input->audio_type - 1]); + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); audio->index = index; audio->capability = V4L2_AUDCAP_STEREO; return 0; @@ -1167,6 +1217,6 @@ int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud memset(aud_output, 0, sizeof(*aud_output)); if (itv->card->video_outputs == NULL || index != 0) return -EINVAL; - strcpy(aud_output->name, "A/V Audio Out"); + strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name)); return 0; } diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 9186fa2ee5fc..748485dcebbd 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -48,7 +48,8 @@ #define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ #define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ #define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ -#define IVTV_CARD_LAST 23 +#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */ +#define IVTV_CARD_LAST 24 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -244,6 +245,7 @@ struct ivtv_card_tuner_i2c { struct ivtv_card { int type; char *name; + char *comment; u32 v4l2_capabilities; u32 hw_video; /* hardware used to process video */ u32 hw_audio; /* hardware used to process audio */ @@ -256,6 +258,7 @@ struct ivtv_card { int nof_outputs; const struct ivtv_card_output *video_outputs; u8 gr_config; /* config byte for the ghost reduction device */ + u8 xceive_pin; /* XCeive tuner GPIO reset pin */ /* GPIO card-specific settings */ struct ivtv_gpio_init gpio_init; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 065df53f80fd..ed020f722b05 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -190,6 +190,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t22 = ASUS Falcon2\n" "\t\t\t23 = AverMedia PVR-150 Plus\n" "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" + "\t\t\t25 = AverMedia M104 (not yet working)\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60"); @@ -871,7 +872,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) unsigned i; /* load modules */ -#ifndef CONFIG_VIDEO_TUNER +#ifndef CONFIG_MEDIA_TUNER hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif #ifndef CONFIG_VIDEO_CX25840 @@ -1048,7 +1049,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ENCODER_SIZE); if (!itv->enc_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); + IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } @@ -1060,7 +1061,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DECODER_SIZE); if (!itv->dec_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); + IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } @@ -1076,7 +1077,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (!itv->reg_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); + IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_io; } @@ -1097,6 +1098,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); } + if (itv->card->comment) + IVTV_INFO("%s", itv->card->comment); + if (itv->card->v4l2_capabilities == 0) { + /* card was detected but is not supported */ + retval = -ENODEV; + goto free_i2c; + } if (itv->std == 0) { itv->std = V4L2_STD_NTSC_M; @@ -1195,13 +1203,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); } - retval = ivtv_streams_setup(itv); - if (retval) { - IVTV_ERR("Error %d setting up streams\n", retval); - goto free_i2c; - } - - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1210,32 +1211,38 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); if (retval) { IVTV_ERR("Failed to register irq %d\n", retval); - goto free_streams; + goto free_i2c; + } + + retval = ivtv_streams_setup(itv); + if (retval) { + IVTV_ERR("Error %d setting up streams\n", retval); + goto free_irq; } retval = ivtv_streams_register(itv); if (retval) { IVTV_ERR("Error %d registering devices\n", retval); - goto free_irq; + goto free_streams; } IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; - free_irq: - free_irq(itv->dev->irq, (void *)itv); - free_streams: +free_streams: ivtv_streams_cleanup(itv); - free_i2c: +free_irq: + free_irq(itv->dev->irq, (void *)itv); +free_i2c: exit_ivtv_i2c(itv); - free_io: +free_io: ivtv_iounmap(itv); - free_mem: +free_mem: release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - free_workqueue: +free_workqueue: destroy_workqueue(itv->irq_work_queues); - err: +err: if (retval == 0) retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index a7640c49f1d8..2b74b0ab1477 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -755,8 +755,10 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); - if (eof || s->q_full.length || s->q_io.length) + if (s->q_full.length || s->q_io.length) return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; return 0; } diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 688cd3856685..d8ac09f3cce6 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -128,20 +128,17 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) { struct i2c_algo_bit_data *algo = dev; struct ivtv *itv = algo->data; - int curdir, curout; + u32 curout; if (cmd != XC2028_TUNER_RESET) return 0; IVTV_DEBUG_INFO("Resetting tuner\n"); curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); + curout &= ~(1 << itv->card->xceive_pin); write_reg(curout, IVTV_REG_GPIO_OUT); schedule_timeout_interruptible(msecs_to_jiffies(1)); - curout |= (1 << 12); + curout |= 1 << itv->card->xceive_pin; write_reg(curout, IVTV_REG_GPIO_OUT); schedule_timeout_interruptible(msecs_to_jiffies(1)); return 0; diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9824eafee021..771adf47e944 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -167,7 +167,8 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) return -1; id = hw_driverids[idx]; memset(&info, 0, sizeof(info)); - strcpy(info.driver_name, hw_drivernames[idx]); + strlcpy(info.driver_name, hw_drivernames[idx], + sizeof(info.driver_name)); info.addr = hw_addrs[idx]; for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 15cac1812122..d508b5d0538c 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -243,20 +243,31 @@ static int ivtv_validate_speed(int cur_speed, int new_speed) int fact = new_speed < 0 ? -1 : 1; int s; - if (new_speed < 0) new_speed = -new_speed; - if (cur_speed < 0) cur_speed = -cur_speed; + if (cur_speed == 0) + cur_speed = 1000; + if (new_speed < 0) + new_speed = -new_speed; + if (cur_speed < 0) + cur_speed = -cur_speed; if (cur_speed <= new_speed) { - if (new_speed > 1500) return fact * 2000; - if (new_speed > 1000) return fact * 1500; + if (new_speed > 1500) + return fact * 2000; + if (new_speed > 1000) + return fact * 1500; } else { - if (new_speed >= 2000) return fact * 2000; - if (new_speed >= 1500) return fact * 1500; - if (new_speed >= 1000) return fact * 1000; - } - if (new_speed == 0) return 1000; - if (new_speed == 1 || new_speed == 1000) return fact * new_speed; + if (new_speed >= 2000) + return fact * 2000; + if (new_speed >= 1500) + return fact * 1500; + if (new_speed >= 1000) + return fact * 1000; + } + if (new_speed == 0) + return 1000; + if (new_speed == 1 || new_speed == 1000) + return fact * new_speed; s = new_speed; new_speed = 1000 / new_speed; @@ -741,10 +752,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_capability *vcap = arg; memset(vcap, 0, sizeof(*vcap)); - strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ - strncpy(vcap->card, itv->card_name, - sizeof(vcap->card)-1); /* card type */ - strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); vcap->version = IVTV_DRIVER_VERSION; /* version */ vcap->capabilities = itv->v4l2_cap; /* capabilities */ @@ -1018,7 +1028,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_std_60hz : ivtv_std_50hz; vs->index = idx; vs->id = enum_stds[idx].std; - strcpy(vs->name, enum_stds[idx].name); + strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); break; } @@ -1102,10 +1112,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strcpy(vt->name, "ivtv Radio Tuner"); + strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); vt->type = V4L2_TUNER_RADIO; } else { - strcpy(vt->name, "ivtv TV Tuner"); + strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); vt->type = V4L2_TUNER_ANALOG_TV; } break; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index a329c4689dbf..d8ba3a4a8761 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -384,7 +384,7 @@ static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) ivtv_stream_sync_for_device(s); write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); add_timer(&itv->dma_timer); } @@ -400,7 +400,7 @@ static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) ivtv_stream_sync_for_device(s); write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); add_timer(&itv->dma_timer); } diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 0f1d4cc4b4d9..02c5ab071d1b 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -23,7 +23,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 #define IVTV_DRIVER_VERSION_MINOR 2 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 0 +#define IVTV_DRIVER_VERSION_PATCHLEVEL 1 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 393d917cd672..62f70bd5e3cb 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -1098,8 +1098,8 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv) ivtv_yuv_next_free(itv); /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ - dma_args.y_source = 0L; - dma_args.uv_source = 0L; + dma_args.y_source = NULL; + dma_args.uv_source = NULL; dma_args.src.left = 0; dma_args.src.top = 0; dma_args.src.width = yi->v4l2_src_w; diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 3b23fc05f7c4..df789f683e63 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -532,7 +532,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "cx23415 TV out"); + strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id)); fix->smem_start = oi->video_pbase; fix->smem_len = oi->video_buffer_size; fix->type = FB_TYPE_PACKED_PIXELS; diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index d4bf14c284ef..5b9dfa2c51b4 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -126,7 +126,8 @@ static int m52790_command(struct i2c_client *client, unsigned int cmd, /* i2c implementation */ -static int m52790_probe(struct i2c_client *client) +static int m52790_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct m52790_state *state; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index b73c740f7fb2..e6273162e123 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -805,7 +805,7 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static int msp_probe(struct i2c_client *client) +static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct msp_state *state; int (*thread_func)(void *data) = NULL; diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 3fb5f63df1e6..179e47049a45 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -372,7 +372,7 @@ static int mt9m001_set_register(struct soc_camera_device *icd, } #endif -const struct v4l2_queryctrl mt9m001_controls[] = { +static const struct v4l2_queryctrl mt9m001_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -620,7 +620,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) soc_camera_video_stop(&mt9m001->icd); } -static int mt9m001_probe(struct i2c_client *client) +static int mt9m001_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct mt9m001 *mt9m001; struct soc_camera_device *icd; @@ -696,12 +697,19 @@ static int mt9m001_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id mt9m001_id[] = { + { "mt9m001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9m001_id); + static struct i2c_driver mt9m001_i2c_driver = { .driver = { .name = "mt9m001", }, .probe = mt9m001_probe, .remove = mt9m001_remove, + .id_table = mt9m001_id, }; static int __init mt9m001_mod_init(void) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index d4b9e2744343..d1391ac55096 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -452,7 +452,7 @@ static int mt9v022_set_register(struct soc_camera_device *icd, } #endif -const struct v4l2_queryctrl mt9v022_controls[] = { +static const struct v4l2_queryctrl mt9v022_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -745,7 +745,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) soc_camera_video_stop(&mt9v022->icd); } -static int mt9v022_probe(struct i2c_client *client) +static int mt9v022_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct mt9v022 *mt9v022; struct soc_camera_device *icd; @@ -818,12 +819,19 @@ static int mt9v022_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id mt9v022_id[] = { + { "mt9v022", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v022_id); + static struct i2c_driver mt9v022_i2c_driver = { .driver = { .name = "mt9v022", }, .probe = mt9v022_probe, .remove = mt9v022_remove, + .id_table = mt9v022_id, }; static int __init mt9v022_mod_init(void) diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 158b3d0c6532..9620c67fae77 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -1,14 +1,15 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C select FW_LOADER - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_SAA711X select VIDEO_CX25840 select VIDEO_MSP3400 select VIDEO_WM8775 + select VIDEO_CS53L32A ---help--- This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -16,32 +17,6 @@ config VIDEO_PVRUSB2 To compile this driver as a module, choose M here: the module will be called pvrusb2 -config VIDEO_PVRUSB2_ONAIR_CREATOR - bool "pvrusb2 driver support for OnAir Creator model" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A - ---help--- - - This option enables support for the OnAir Creator USB tuner - device. This is a hybrid device, however currently only - analog mode is supported. - - If you are in doubt, say Y. - -config VIDEO_PVRUSB2_ONAIR_USB2 - bool "pvrusb2 driver support for OnAir USB2 model" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A - ---help--- - - This option enables support for the OnAir USB2 tuner device - (also known as the Sasem tuner). This is a hybrid device, - however currently only analog mode is supported. - - If you are in doubt, say Y. - config VIDEO_PVRUSB2_SYSFS bool "pvrusb2 sysfs support (EXPERIMENTAL)" default y @@ -59,29 +34,23 @@ config VIDEO_PVRUSB2_SYSFS Note: This feature is experimental and subject to change. config VIDEO_PVRUSB2_DVB - bool "pvrusb2 DVB support (EXPERIMENTAL)" - default n + bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)" + default y depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE ---help--- - This option enables compilation of a DVB interface for the - pvrusb2 driver. Currently this is very very experimental. - It is also limiting - the DVB interface can only access the - digital side of hybrid devices, and there are going to be - issues if you attempt to mess with the V4L side at the same - time. Don't turn this on unless you know what you are - doing. - - If you are in doubt, say N. + This option enables a DVB interface for the pvrusb2 driver. + If your device does not support digital television, this + feature will have no affect on the driver's operation. - Note: This feature is very experimental and might break + If you are in doubt, say Y. config VIDEO_PVRUSB2_DEBUGIFC bool "pvrusb2 debug interface" diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index 5b3083c89aa9..4fda2de69ab7 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -16,5 +16,6 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 9a7c8e9c3e8b..8d859ccd48ec 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -75,7 +75,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt) pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { route.input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index b5db6a5bab31..73dcb1c57ae6 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -195,7 +195,7 @@ static int pvr2_context_thread_func(void *foo) int pvr2_context_global_init(void) { pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func, - 0, + NULL, "pvrusb2-context"); return (pvr2_context_thread_ptr ? 0 : -ENOMEM); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 97350b048b8d..29d50597c88a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -123,7 +123,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt) memset(&route,0,sizeof(route)); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { vid_input = sp->def[hdw->input_val].vid; diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index 11537ddf8aa3..707d2d9635d7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -54,6 +54,7 @@ extern int pvrusb2_debug; #define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ #define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ #define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ +#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 3a141d93e1a9..5bf6d8fda1f9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -153,7 +153,6 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = { -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR /*------------------------------------------------------------------------*/ /* OnAir Creator */ @@ -212,11 +211,9 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = { .dvb_props = &pvr2_onair_creator_fe_props, #endif }; -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 /*------------------------------------------------------------------------*/ /* OnAir USB 2.0 */ @@ -274,7 +271,6 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = { .dvb_props = &pvr2_onair_usb2_fe_props, #endif }; -#endif @@ -497,14 +493,10 @@ struct usb_device_id pvr2_device_table[] = { .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, { USB_DEVICE(0x1164, 0x0602), .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d}, -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR { USB_DEVICE(0x11ba, 0x1003), .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 { USB_DEVICE(0x11ba, 0x1001), .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, -#endif { USB_DEVICE(0x2040, 0x7300), .driver_info = (kernel_ulong_t)&pvr2_device_73xxx}, { USB_DEVICE(0x2040, 0x7500), diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 2e64f98d1241..6ec4bf81fc7f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -21,6 +21,7 @@ #include <linux/kthread.h> #include <linux/freezer.h> #include "dvbdev.h" +#include "pvrusb2-debug.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" @@ -35,7 +36,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) struct pvr2_buffer *bp; struct pvr2_stream *stream; - printk(KERN_DEBUG "dvb thread started\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started"); set_freezable(); stream = adap->channel.stream->stream; @@ -82,7 +83,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) /* If we get here and ret is < 0, then an error has occurred. Probably would be a good idea to communicate that to DVB core... */ - printk(KERN_DEBUG "dvb thread stopped\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped"); return 0; } @@ -130,7 +131,7 @@ static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { if (!(adap->buffer_storage[idx])) continue; kfree(adap->buffer_storage[idx]); - adap->buffer_storage[idx] = 0; + adap->buffer_storage[idx] = NULL; } adap->stream_run = 0; } @@ -142,7 +143,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) unsigned int idx; int ret; struct pvr2_buffer *bp; - struct pvr2_stream *stream = 0; + struct pvr2_stream *stream = NULL; if (adap->stream_run) return -EIO; @@ -174,7 +175,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1); if (ret < 0) return ret; - while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) { + while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) { ret = pvr2_buffer_queue(bp); if (ret < 0) return ret; } @@ -210,7 +211,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) do { if (onoff) { if (!adap->feedcount) { - printk(KERN_DEBUG "start feeding\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, + "start feeding demux"); ret = pvr2_dvb_stream_start(adap); if (ret < 0) break; } @@ -218,7 +220,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } else if (adap->feedcount > 0) { (adap->feedcount)--; if (!adap->feedcount) { - printk(KERN_DEBUG "stop feeding\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, + "stop feeding demux"); pvr2_dvb_stream_end(adap); } } @@ -230,15 +233,13 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid); return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); } static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid); return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); } @@ -259,7 +260,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) &adap->channel.hdw->usb_dev->dev, adapter_nr); if (ret < 0) { - err("dvb_register_adapter failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_register_adapter failed: error %d", ret); goto err; } adap->dvb_adap.priv = adap; @@ -276,7 +278,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_dmx_init(&adap->demux); if (ret < 0) { - err("dvb_dmx_init failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_dmx_init failed: error %d", ret); goto err_dmx; } @@ -286,7 +289,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); if (ret < 0) { - err("dvb_dmxdev_init failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } @@ -304,7 +308,7 @@ err: static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) { - printk(KERN_DEBUG "unregistering DVB devices\n"); + pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices"); dvb_net_release(&adap->dvb_net); adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); @@ -320,7 +324,7 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) int ret = 0; if (dvb_props == NULL) { - err("fe_props not defined!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!"); return -EINVAL; } @@ -328,13 +332,15 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) &adap->channel, (1 << PVR2_CVAL_INPUT_DTV)); if (ret) { - err("failed to grab control of dtv input (code=%d)", + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "failed to grab control of dtv input (code=%d)", ret); return ret; } if (dvb_props->frontend_attach == NULL) { - err("frontend_attach not defined!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend_attach not defined!"); ret = -EINVAL; goto done; } @@ -342,7 +348,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { - err("frontend registration failed!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend registration failed!"); dvb_frontend_detach(adap->fe); adap->fe = NULL; ret = -ENODEV; @@ -359,7 +366,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; } else { - err("no frontend was attached!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "no frontend was attached!"); ret = -ENODEV; return ret; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 087a18245560..e9b5d4e91327 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1261,7 +1261,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) fail: pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp); pvr2_v4l2_destroy_no_lock(vp); - return 0; + return NULL; } /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 7c47345501b6..2433a3160041 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -81,7 +81,7 @@ static void set_input(struct pvr2_v4l_decoder *ctxt) pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { route.input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 416d05d4a969..e684108637ad 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1450,7 +1450,8 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static int saa7115_probe(struct i2c_client *client) +static int saa7115_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct saa711x_state *state; int i; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 06c88db656b4..e750cd65c1c3 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -661,7 +661,8 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_client *client) +static int saa7127_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index e086f14d5663..40e4c3bd2cb9 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SAA7134 depends on VIDEO_DEV && PCI && I2C && INPUT select VIDEOBUF_DMA_SG select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select CRC32 ---help--- @@ -35,9 +35,9 @@ config VIDEO_SAA7134_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_TDA827X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 9aff937ba7a5..3dbaa19a6d00 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -11,5 +11,6 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 98375955a84b..b111903aa322 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -47,6 +47,9 @@ static char name_svideo[] = "S-Video"; /* ------------------------------------------------------------------ */ /* board config info */ +/* If radio_type !=UNSET, radio_addr should be specified + */ + struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", @@ -3087,7 +3090,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_type = TUNER_PHILIPS_TD1316, /* untested */ .radio_type = TUNER_TEA5767, /* untested */ .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, + .radio_addr = 0x60, .tda9887_conf = TDA9887_PRESENT, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -4247,6 +4250,36 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, } }, }, + [SAA7134_BOARD_BEHOLD_H6] = { + /* Igor Kuznetsov <igk@igk.ru> */ + .name = "Beholder BeholdTV H6", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + /* no DVB support for now */ + /* .mpeg = SAA7134_MPEG_DVB, */ + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -5197,6 +5230,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x5ace, .subdevice = 0x6193, .driver_data = SAA7134_BOARD_BEHOLD_M6, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6191, + .driver_data = SAA7134_BOARD_BEHOLD_M6, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -5246,6 +5285,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xc900, .driver_data = SAA7134_BOARD_VIDEOMATE_T750, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6290, + .driver_data = SAA7134_BOARD_BEHOLD_H6, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5577,20 +5622,87 @@ int saa7134_board_init1(struct saa7134_dev *dev) return 0; } +static void saa7134_tuner_setup(struct saa7134_dev *dev) +{ + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | + T_ANALOG_TV | + T_DIGITAL_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.tuner_callback = saa7134_tuner_callback; + + if (saa7134_boards[dev->board].radio_type != UNSET) { + tun_setup.type = saa7134_boards[dev->board].radio_type; + tun_setup.addr = saa7134_boards[dev->board].radio_addr; + + tun_setup.mode_mask = T_RADIO; + + saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) { + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.config = saa7134_boards[dev->board].tuner_config; + tun_setup.tuner_callback = saa7134_tuner_callback; + + tun_setup.mode_mask = mode_mask; + + saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + if (dev->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); + } + + if (dev->tuner_type == TUNER_XC2028) { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset(&xc2028_cfg, 0, sizeof(ctl)); + memset(&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + + switch (dev->board) { + case SAA7134_BOARD_AVERMEDIA_A16D: + ctl.demod = XC3028_FE_ZARLINK456; + break; + default: + ctl.demod = XC3028_FE_OREN538; + ctl.mts = 1; + } + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } +} + /* stuff which needs working i2c */ int saa7134_board_init2(struct saa7134_dev *dev) { unsigned char buf; int board; - struct tuner_setup tun_setup; - tun_setup.config = 0; - tun_setup.tuner_callback = saa7134_tuner_callback; + + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: case SAA7134_BOARD_BMK_MPEX_TUNER: dev->i2c_client.addr = 0x60; - board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0) + board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0) ? SAA7134_BOARD_BMK_MPEX_NOTUNER : SAA7134_BOARD_BMK_MPEX_TUNER; if (board == dev->board) @@ -5600,21 +5712,9 @@ int saa7134_board_init2(struct saa7134_dev *dev) saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; - if (TUNER_ABSENT != dev->tuner_type) { - tun_setup.mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = ADDR_UNSET; - tun_setup.tuner_callback = saa7134_tuner_callback; - - saa7134_i2c_call_clients(dev, - TUNER_SET_TYPE_ADDR, - &tun_setup); - } break; case SAA7134_BOARD_MD7134: - { + { u8 subaddr; u8 data[3]; int ret, tuner_t; @@ -5667,30 +5767,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) } printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); - if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); - } - - tun_setup.mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = ADDR_UNSET; - - saa7134_i2c_call_clients(dev, - TUNER_SET_TYPE_ADDR, &tun_setup); - } break; + } case SAA7134_BOARD_PHILIPS_EUROPA: if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) { /* Reconfigure board as Snake reference design */ @@ -5702,43 +5780,43 @@ int saa7134_board_init2(struct saa7134_dev *dev) } case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: + { + /* The Philips EUROPA based hybrid boards have the tuner connected through * the channel decoder. We have to make it transparent to find it */ - { u8 data[] = { 0x07, 0x02}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); - } break; + } case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: - { + { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - if(dev->autodetected && (dev->eedata[0x49] == 0x50)) { + if (dev->autodetected && (dev->eedata[0x49] == 0x50)) { dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; printk(KERN_INFO "%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } - if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = TUNER_PHILIPS_TDA8290; - tun_setup.addr = 0x4b; - tun_setup.config = 2; + if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { + dev->tuner_type = TUNER_PHILIPS_TDA8290; + + saa7134_tuner_setup(dev); - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); data[2] = 0x68; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + /* Tuner setup is handled before I2C transfer. + Due to that, there's no need to do it later + */ + return 0; } i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_HAUPPAUGE_HVR1110: hauppauge_eeprom(dev, dev->eedata+0x80); /* break intentionally omitted */ @@ -5751,52 +5829,55 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_SUPER_007: case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: case SAA7134_BOARD_CREATIX_CTX953: + { /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ - { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_FLYDVB_TRIO: - { + { u8 data[] = { 0x3c, 0x33, 0x62}; struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: + { /* initialize analog mode */ - { u8 data[] = { 0x3c, 0x33, 0x6a}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_CINERGY_HT_PCMCIA: case SAA7134_BOARD_CINERGY_HT_PCI: + { /* initialize analog mode */ - { u8 data[] = { 0x3c, 0x33, 0x68}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_KWORLD_ATSC110: - { - /* enable tuner */ - int i; - static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; - dev->i2c_client.addr = 0x0a; - for (i = 0; i < 5; i++) - if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2)) - printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", - dev->name, i); - } + { + /* enable tuner */ + int i; + static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16, + 0x00, 0x14, 0x04, 0x17, 0x00 }; + dev->i2c_client.addr = 0x0a; + for (i = 0; i < 5; i++) + if (2 != i2c_master_send(&dev->i2c_client, + &buffer[i*2], 2)) + printk(KERN_WARNING + "%s: Unable to enable tuner(%i).\n", + dev->name, i); break; + } case SAA7134_BOARD_VIDEOMATE_DVBT_200: case SAA7134_BOARD_VIDEOMATE_DVBT_200A: /* The T200 and the T200A share the same pci id. Consequently, @@ -5821,7 +5902,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: - { + { struct v4l2_priv_tun_config tea5767_cfg; struct tea5767_ctrl ctl; @@ -5832,34 +5913,11 @@ int saa7134_board_init2(struct saa7134_dev *dev) tea5767_cfg.tuner = TUNER_TEA5767; tea5767_cfg.priv = &ctl; saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg); - } break; } + } /* switch() */ - if (dev->tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(ctl)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; - - switch (dev->board) { - case SAA7134_BOARD_AVERMEDIA_A16D: - ctl.demod = XC3028_FE_ZARLINK456; - break; - default: - ctl.demod = XC3028_FE_OREN538; - ctl.mts = 1; - } - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); - } + saa7134_tuner_setup(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 2ccfaba0c490..d8af3863f2d3 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -324,8 +324,6 @@ static u32 functionality(struct i2c_adapter *adap) static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; - int tuner = dev->tuner_type; - struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -346,46 +344,6 @@ static int attach_inform(struct i2c_client *client) } } - if (!client->driver->command) - return 0; - - if (saa7134_boards[dev->board].radio_type != UNSET) { - - tun_setup.type = saa7134_boards[dev->board].radio_type; - tun_setup.addr = saa7134_boards[dev->board].radio_addr; - - if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) { - tun_setup.mode_mask = T_RADIO; - - client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - - if (tuner != UNSET) { - tun_setup.type = tuner; - tun_setup.addr = saa7134_boards[dev->board].tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; - tun_setup.tuner_callback = saa7134_tuner_callback; - - if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { - - tun_setup.mode_mask = T_ANALOG_TV; - - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); - } - - if (tuner == TUNER_TDA9887) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, - &tda9887_cfg); - } - } - - return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 767ff30832f2..919632b10aae 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -531,6 +531,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) break; case SAA7134_BOARD_BEHOLD_607_9FM: case SAA7134_BOARD_BEHOLD_M6: + case SAA7134_BOARD_BEHOLD_H6: snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); ir->get_key = get_key_beholdm6xx; ir->ir_codes = ir_codes_behold; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 924ffd13637e..34ff0d4998f3 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -263,6 +263,7 @@ struct saa7134_format { #define SAA7134_BOARD_VIDEOMATE_T750 139 #define SAA7134_BOARD_AVERMEDIA_A700_PRO 140 #define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141 +#define SAA7134_BOARD_BEHOLD_H6 142 #define SAA7134_MAXBOARDS 8 diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 53c5edbcf7ea..72c4081feff5 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1418,7 +1418,8 @@ static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ /* ----------------------------------------------------------------------- */ -static int saa717x_probe(struct i2c_client *client) +static int saa717x_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct saa717x_state *decoder; u8 id = 0; diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 6943b447a1bd..e57a64605778 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -840,7 +840,8 @@ static struct v4l2_int_device tcm825x_int_device = { }, }; -static int tcm825x_probe(struct i2c_client *client) +static int tcm825x_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct tcm825x_sensor *sensor = &tcm825x; int rval; diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index dc7b9c220b90..f1db54202dea 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -125,7 +125,8 @@ static int tlv320aic23b_command(struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int tlv320aic23b_probe(struct i2c_client *client) +static int tlv320aic23b_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tlv320aic23b_state *state; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2b72e10e6b9f..6bf104ea051d 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -33,6 +33,46 @@ #define PREFIX t->i2c->driver->driver.name +/** This macro allows us to probe dynamically, avoiding static links */ +#ifdef CONFIG_MEDIA_ATTACH +#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ + int __r = -EINVAL; \ + typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ + if (__a) { \ + __r = (int) __a(ARGS); \ + } else { \ + printk(KERN_ERR "TUNER: Unable to find " \ + "symbol "#FUNCTION"()\n"); \ + } \ + symbol_put(FUNCTION); \ + __r; \ +}) + +static void tuner_detach(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.release) { + fe->ops.tuner_ops.release(fe); + symbol_put_addr(fe->ops.tuner_ops.release); + } + if (fe->ops.analog_ops.release) { + fe->ops.analog_ops.release(fe); + symbol_put_addr(fe->ops.analog_ops.release); + } +} +#else +#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ +}) + +static void tuner_detach(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + if (fe->ops.analog_ops.release) + fe->ops.analog_ops.release(fe); +} +#endif + struct tuner { /* device */ struct dvb_frontend fe; @@ -56,7 +96,7 @@ struct tuner { /* standard i2c insmod options */ static unsigned short normal_i2c[] = { -#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) 0x10, #endif 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ @@ -139,22 +179,6 @@ static void fe_set_params(struct dvb_frontend *fe, fe_tuner_ops->set_analog_params(fe, params); } -static void fe_release(struct dvb_frontend *fe) -{ - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - - /* DO NOT kfree(fe->analog_demod_priv) - * - * If we are in this function, analog_demod_priv contains a pointer - * to struct tuner *t. This will be kfree'd in tuner_detach(). - * - * Otherwise, fe->ops.analog_demod_ops->release will - * handle the cleanup for analog demodulator modules. - */ - fe->analog_demod_priv = NULL; -} - static void fe_standby(struct dvb_frontend *fe) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; @@ -191,7 +215,6 @@ static void tuner_status(struct dvb_frontend *fe); static struct analog_demod_ops tuner_core_ops = { .set_params = fe_set_params, .standby = fe_standby, - .release = fe_release, .has_signal = fe_has_signal, .set_config = fe_set_config, .tuner_status = tuner_status @@ -323,7 +346,8 @@ static void attach_tda829x(struct tuner *t) .lna_cfg = t->config, .tuner_callback = t->tuner_callback, }; - tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); + dvb_attach(tda829x_attach, + &t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } static struct xc5000_config xc5000_cfg; @@ -356,12 +380,13 @@ static void set_type(struct i2c_client *c, unsigned int type, } /* discard private data, in case set_type() was previously called */ - if (analog_ops->release) - analog_ops->release(&t->fe); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + dvb_attach(microtune_attach, + &t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_PHILIPS_TDA8290: { @@ -369,12 +394,14 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) + if (!dvb_attach(tea5767_attach, &t->fe, + t->i2c->adapter, t->i2c->addr)) goto attach_failed; t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) + if (!dvb_attach(tea5761_attach, &t->fe, + t->i2c->adapter, t->i2c->addr)) goto attach_failed; t->mode_mask = T_RADIO; break; @@ -388,8 +415,8 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, - t->type)) + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; case TUNER_PHILIPS_TD1316: @@ -397,9 +424,9 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[1] = 0xdc; buffer[2] = 0x86; buffer[3] = 0xa4; - i2c_master_send(c,buffer,4); - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, - t->i2c->addr, t->type)) + i2c_master_send(c, buffer, 4); + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; case TUNER_XC2028: @@ -409,12 +436,13 @@ static void set_type(struct i2c_client *c, unsigned int type, .i2c_addr = t->i2c->addr, .callback = t->tuner_callback, }; - if (!xc2028_attach(&t->fe, &cfg)) + if (!dvb_attach(xc2028_attach, &t->fe, &cfg)) goto attach_failed; break; } case TUNER_TDA9887: - tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + dvb_attach(tda9887_attach, + &t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_XC5000: { @@ -424,7 +452,8 @@ static void set_type(struct i2c_client *c, unsigned int type, xc5000_cfg.if_khz = 5380; xc5000_cfg.priv = c->adapter->algo_data; xc5000_cfg.tuner_callback = t->tuner_callback; - if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) + if (!dvb_attach(xc5000_attach, + &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; xc_tuner_ops = &t->fe.ops.tuner_ops; @@ -433,8 +462,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } default: - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, - t->i2c->addr, t->type)) + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; @@ -442,12 +471,14 @@ static void set_type(struct i2c_client *c, unsigned int type, if ((NULL == analog_ops->set_params) && (fe_tuner_ops->set_analog_params)) { + strlcpy(t->i2c->name, fe_tuner_ops->info.name, sizeof(t->i2c->name)); t->fe.analog_demod_priv = t; memcpy(analog_ops, &tuner_core_ops, sizeof(struct analog_demod_ops)); + } else { strlcpy(t->i2c->name, analog_ops->info.name, sizeof(t->i2c->name)); @@ -645,8 +676,8 @@ static void tuner_status(struct dvb_frontend *fe) { struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; const char *p; switch (t->mode) { @@ -730,8 +761,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (tuner_debug>1) + if (tuner_debug > 1) { v4l_i2c_print_ioctl(client,cmd); + printk("\n"); + } switch (cmd) { /* --- configuration --- */ @@ -1073,7 +1106,8 @@ static void tuner_lookup(struct i2c_adapter *adap, /* During client attach, set_type is called by adapter's attach_inform callback. set_type must then be completed by tuner_probe. */ -static int tuner_probe(struct i2c_client *client) +static int tuner_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tuner *t; struct tuner *radio; @@ -1111,8 +1145,9 @@ static int tuner_probe(struct i2c_client *client) if (!no_autodetect) { switch (client->addr) { case 0x10: - if (tea5761_autodetection(t->i2c->adapter, - t->i2c->addr) >= 0) { + if (tuner_symbol_probe(tea5761_autodetection, + t->i2c->adapter, + t->i2c->addr) >= 0) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -1131,8 +1166,8 @@ static int tuner_probe(struct i2c_client *client) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda829x_probe(t->i2c->adapter, - t->i2c->addr) == 0) { + if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, + t->i2c->addr) == 0) { tuner_dbg("tda829x detected\n"); } else { /* Default is being tda9887 */ @@ -1144,7 +1179,8 @@ static int tuner_probe(struct i2c_client *client) } break; case 0x60: - if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) + if (tuner_symbol_probe(tea5767_autodetection, + t->i2c->adapter, t->i2c->addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; @@ -1233,10 +1269,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) static int tuner_remove(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (analog_ops->release) - analog_ops->release(&t->fe); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; list_del(&t->list); kfree(t); diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index f29a2cd0f2f2..6f9945b04e1f 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1461,7 +1461,7 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_probe(struct i2c_client *client) +static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct CHIPSTATE *chip; struct CHIPDESC *desc; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index bd201397a2ac..93bfd19dec7d 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -195,7 +195,8 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64031a_probe(struct i2c_client *client) +static int upd64031a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct upd64031a_state *state; int i; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 2d9a88f70c85..9ab712a56ce0 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -172,7 +172,8 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64083_probe(struct i2c_client *client) +static int upd64083_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct upd64083_state *state; int i; diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 64819353276a..17f542dfb366 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/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig index fc24ef05b3f3..74e1d3075a20 100644 --- a/drivers/media/video/usbvision/Kconfig +++ b/drivers/media/video/usbvision/Kconfig @@ -1,7 +1,7 @@ config VIDEO_USBVISION tristate "USB video devices based on Nogatech NT1003/1004/1005" depends on I2C && VIDEO_V4L2 - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO ---help--- There are more than 50 different USB video devices based on diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index 9ac92a80c645..338718750945 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -3,3 +3,4 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision- obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 34deb68ae568..e9dd996fd5df 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -710,13 +710,14 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); /* Helper function for I2C legacy drivers */ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, - const char *name, int (*probe)(struct i2c_client *)) + const char *name, + int (*probe)(struct i2c_client *, const struct i2c_device_id *)) { struct i2c_client *client; int err; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; @@ -724,7 +725,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver client->driver = driver; strlcpy(client->name, name, sizeof(client->name)); - err = probe(client); + err = probe(client, NULL); if (err == 0) { i2c_attach_client(client); } else { diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index fc51e4918bbf..982f4463896c 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -97,7 +97,10 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, void *videobuf_queue_to_vmalloc (struct videobuf_queue *q, struct videobuf_buffer *buf) { - return CALL(q, vmalloc, buf); + if (q->int_ops->vmalloc) + return q->int_ops->vmalloc(buf); + else + return NULL; } EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc); diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index d545c98dd5e7..01ea99c9bc1a 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -13,7 +13,7 @@ /* * TODO: * - remove "mark pages reserved-hacks" from memory allocation code - * and implement nopage() + * and implement fault() * - check decimation, calculating and reporting image size when * using decimation * - implement read(), user mode buffers and overlay (?) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 282c81403c97..fac0deba24af 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -121,7 +121,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int vp27smpx_probe(struct i2c_client *client) +static int vp27smpx_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct vp27smpx_state *state; diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 31795b4f8b63..0f8ed8461fba 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -261,7 +261,8 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int wm8739_probe(struct i2c_client *client) +static int wm8739_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8739_state *state; diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 869f9e7946b6..67a409e60c46 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -159,7 +159,8 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int wm8775_probe(struct i2c_client *client) +static int wm8775_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8775_state *state; diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index 328ed6e7ac6a..870bc5a70e3f 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -180,6 +180,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer, } static const struct file_operations zoran_operations = { + .owner = THIS_MODULE, .open = zoran_open, .read = seq_read, .write = zoran_write, @@ -195,10 +196,8 @@ zoran_proc_init (struct zoran *zr) char name[8]; snprintf(name, 7, "zoran%d", zr->id); - if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) { - zr->zoran_proc->data = zr; - zr->zoran_proc->owner = THIS_MODULE; - zr->zoran_proc->proc_fops = &zoran_operations; + zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr); + if (zr->zoran_proc != NULL) { dprintk(2, KERN_INFO "%s: procfs entry /proc/%s allocated. data=%p\n", diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index a95314897402..81483de8c0fd 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -371,7 +371,7 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) /* connect the i2o_block_request to the request */ if (!req->special) { ireq = i2o_block_request_alloc(); - if (unlikely(IS_ERR(ireq))) { + if (IS_ERR(ireq)) { osm_debug("unable to allocate i2o_block_request!\n"); return BLKPREP_DEFER; } diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index 6fdd072201f9..54a3016ff45d 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -1893,13 +1893,11 @@ static int i2o_proc_create_entries(struct proc_dir_entry *dir, struct proc_dir_entry *tmp; while (i2o_pe->name) { - tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir); + tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir, + i2o_pe->fops, data); if (!tmp) return -1; - tmp->data = data; - tmp->proc_fops = i2o_pe->fops; - i2o_pe++; } diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index f6f2d960cadb..ef8a492766a7 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/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 4edc120a6359..633cbba072f0 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -132,8 +132,9 @@ static struct ds1wm_platform_data ds1wm_pdata = { .disable = ds1wm_disable, }; -static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift) +static int ds1wm_device_add(struct platform_device *pasic3_pdev, int bus_shift) { + struct device *pasic3_dev = &pasic3_pdev->dev; struct pasic3_data *asic = pasic3_dev->driver_data; struct platform_device *pdev; int ret; @@ -144,8 +145,8 @@ static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift) return -ENOMEM; } - ret = platform_device_add_resources(pdev, pdev->resource, - pdev->num_resources); + ret = platform_device_add_resources(pdev, pasic3_pdev->resource, + pasic3_pdev->num_resources); if (ret < 0) { dev_dbg(pasic3_dev, "failed to add DS1WM resources\n"); goto exit_pdev_put; @@ -207,7 +208,7 @@ static int __init pasic3_probe(struct platform_device *pdev) return -ENOMEM; } - ret = ds1wm_device_add(dev, asic->bus_shift); + ret = ds1wm_device_add(pdev, asic->bus_shift); if (ret < 0) dev_warn(dev, "failed to register DS1WM\n"); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 13bac53db69a..2fe64734d8af 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -22,6 +22,7 @@ #include <linux/sm501.h> #include <linux/sm501-regs.h> +#include <linux/serial_8250.h> #include <asm/io.h> @@ -348,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) { @@ -723,13 +724,14 @@ static void sm501_device_release(struct device *dev) */ static struct platform_device * -sm501_create_subdev(struct sm501_devdata *sm, - char *name, unsigned int res_count) +sm501_create_subdev(struct sm501_devdata *sm, char *name, + unsigned int res_count, unsigned int platform_data_size) { struct sm501_device *smdev; smdev = kzalloc(sizeof(struct sm501_device) + - sizeof(struct resource) * res_count, GFP_KERNEL); + (sizeof(struct resource) * res_count) + + platform_data_size, GFP_KERNEL); if (!smdev) return NULL; @@ -737,11 +739,15 @@ sm501_create_subdev(struct sm501_devdata *sm, smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; - smdev->pdev.resource = (struct resource *)(smdev+1); - smdev->pdev.num_resources = res_count; - smdev->pdev.dev.parent = sm->dev; + if (res_count) { + smdev->pdev.resource = (struct resource *)(smdev+1); + smdev->pdev.num_resources = res_count; + } + if (platform_data_size) + smdev->pdev.dev.platform_data = (void *)(smdev+1); + return &smdev->pdev; } @@ -829,7 +835,7 @@ static int sm501_register_usbhost(struct sm501_devdata *sm, { struct platform_device *pdev; - pdev = sm501_create_subdev(sm, "sm501-usb", 3); + pdev = sm501_create_subdev(sm, "sm501-usb", 3, 0); if (!pdev) return -ENOMEM; @@ -840,12 +846,55 @@ static int sm501_register_usbhost(struct sm501_devdata *sm, return sm501_register_device(sm, pdev); } +static void sm501_setup_uart_data(struct sm501_devdata *sm, + struct plat_serial8250_port *uart_data, + unsigned int offset) +{ + uart_data->membase = sm->regs + offset; + uart_data->mapbase = sm->io_res->start + offset; + uart_data->iotype = UPIO_MEM; + uart_data->irq = sm->irq; + uart_data->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + uart_data->regshift = 2; + uart_data->uartclk = (9600 * 16); +} + +static int sm501_register_uart(struct sm501_devdata *sm, int devices) +{ + struct platform_device *pdev; + struct plat_serial8250_port *uart_data; + + pdev = sm501_create_subdev(sm, "serial8250", 0, + sizeof(struct plat_serial8250_port) * 3); + if (!pdev) + return -ENOMEM; + + uart_data = pdev->dev.platform_data; + + if (devices & SM501_USE_UART0) { + sm501_setup_uart_data(sm, uart_data++, 0x30000); + sm501_unit_power(sm->dev, SM501_GATE_UART0, 1); + sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 12, 0); + sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x01e0, 0); + } + if (devices & SM501_USE_UART1) { + sm501_setup_uart_data(sm, uart_data++, 0x30020); + sm501_unit_power(sm->dev, SM501_GATE_UART1, 1); + sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 13, 0); + sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x1e00, 0); + } + + pdev->id = PLAT8250_DEV_SM501; + + return sm501_register_device(sm, pdev); +} + static int sm501_register_display(struct sm501_devdata *sm, resource_size_t *mem_avail) { struct platform_device *pdev; - pdev = sm501_create_subdev(sm, "sm501-fb", 4); + pdev = sm501_create_subdev(sm, "sm501-fb", 4, 0); if (!pdev) return -ENOMEM; @@ -963,6 +1012,7 @@ static unsigned int sm501_mem_local[] = { static int sm501_init_dev(struct sm501_devdata *sm) { + struct sm501_initdata *idata; resource_size_t mem_avail; unsigned long dramctrl; unsigned long devid; @@ -980,6 +1030,9 @@ static int sm501_init_dev(struct sm501_devdata *sm) return -EINVAL; } + /* disable irqs */ + writel(0, sm->regs + SM501_IRQ_MASK); + dramctrl = readl(sm->regs + SM501_DRAM_CONTROL); mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; @@ -998,15 +1051,14 @@ static int sm501_init_dev(struct sm501_devdata *sm) /* check to see if we have some device initialisation */ - if (sm->platdata) { - struct sm501_platdata *pdata = sm->platdata; + idata = sm->platdata ? sm->platdata->init : NULL; + if (idata) { + sm501_init_regs(sm, idata); - if (pdata->init) { - sm501_init_regs(sm, sm->platdata->init); - - if (pdata->init->devices & SM501_USE_USB_HOST) - sm501_register_usbhost(sm, &mem_avail); - } + if (idata->devices & SM501_USE_USB_HOST) + sm501_register_usbhost(sm, &mem_avail); + if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1)) + sm501_register_uart(sm, idata->devices); } ret = sm501_check_clocks(sm); diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 5e859486eaf8..ad34e2d22524 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -204,8 +204,7 @@ static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts) static int ucb1x00_thread(void *_ts) { struct ucb1x00_ts *ts = _ts; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); + DECLARE_WAITQUEUE(wait, current); int valid = 0; set_freezable(); @@ -234,7 +233,7 @@ static int ucb1x00_thread(void *_ts) if (ucb1x00_ts_pen_down(ts)) { - set_task_state(tsk, TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); ucb1x00_disable(ts->ucb); @@ -262,7 +261,7 @@ static int ucb1x00_thread(void *_ts) valid = 1; } - set_task_state(tsk, TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); timeout = HZ / 100; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 297a48f85446..636af2862308 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -140,6 +140,7 @@ config ACER_WMI depends on EXPERIMENTAL depends on ACPI depends on LEDS_CLASS + depends on NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 select ACPI_WMI @@ -160,6 +161,7 @@ config ASUS_LAPTOP depends on ACPI depends on EXPERIMENTAL && !ACPI_ASUS depends on LEDS_CLASS + depends on NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE ---help--- This is the new Linux driver for Asus laptops. It may also support some @@ -241,10 +243,13 @@ config SONYPI_COMPAT config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" depends on X86 && ACPI + select BACKLIGHT_LCD_SUPPORT select BACKLIGHT_CLASS_DEVICE select HWMON select NVRAM - depends on INPUT + select INPUT + select NEW_LEDS + select LEDS_CLASS ---help--- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video @@ -344,6 +349,7 @@ config ATMEL_SSC config INTEL_MENLOW tristate "Thermal Management driver for Intel menlow platform" depends on ACPI_THERMAL + select THERMAL depends on X86 ---help--- ACPI thermal management enhancement driver on @@ -351,6 +357,19 @@ config INTEL_MENLOW If unsure, say N. +config EEEPC_LAPTOP + tristate "Eee PC Hotkey Driver (EXPERIMENTAL)" + depends on X86 + depends on ACPI + depends on BACKLIGHT_CLASS_DEVICE + depends on HWMON + depends on EXPERIMENTAL + ---help--- + This driver supports the Fn-Fx keys on Eee PC laptops. + It also adds the ability to switch camera/wlan on/off. + + If you have an Eee PC laptop, say Y or M here. + config ENCLOSURE_SERVICES tristate "Enclosure Services" default n diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5914da434854..1952875a272e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -7,7 +7,8 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o -obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c new file mode 100644 index 000000000000..6d727609097f --- /dev/null +++ b/drivers/misc/eeepc-laptop.c @@ -0,0 +1,666 @@ +/* + * eepc-laptop.c - Asus Eee PC extras + * + * Based on asus_acpi.c as patched for the Eee PC by Asus: + * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar + * Based on eee.c from eeepc-linux + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <linux/backlight.h> +#include <linux/fb.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <acpi/acpi_drivers.h> +#include <acpi/acpi_bus.h> +#include <linux/uaccess.h> + +#define EEEPC_LAPTOP_VERSION "0.1" + +#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver" +#define EEEPC_HOTK_FILE "eeepc" +#define EEEPC_HOTK_CLASS "hotkey" +#define EEEPC_HOTK_DEVICE_NAME "Hotkey" +#define EEEPC_HOTK_HID "ASUS010" + +#define EEEPC_LOG EEEPC_HOTK_FILE ": " +#define EEEPC_ERR KERN_ERR EEEPC_LOG +#define EEEPC_WARNING KERN_WARNING EEEPC_LOG +#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG +#define EEEPC_INFO KERN_INFO EEEPC_LOG + +/* + * Definitions for Asus EeePC + */ +#define NOTIFY_WLAN_ON 0x10 +#define NOTIFY_BRN_MIN 0x20 +#define NOTIFY_BRN_MAX 0x2f + +enum { + DISABLE_ASL_WLAN = 0x0001, + DISABLE_ASL_BLUETOOTH = 0x0002, + DISABLE_ASL_IRDA = 0x0004, + DISABLE_ASL_CAMERA = 0x0008, + DISABLE_ASL_TV = 0x0010, + DISABLE_ASL_GPS = 0x0020, + DISABLE_ASL_DISPLAYSWITCH = 0x0040, + DISABLE_ASL_MODEM = 0x0080, + DISABLE_ASL_CARDREADER = 0x0100 +}; + +enum { + CM_ASL_WLAN = 0, + CM_ASL_BLUETOOTH, + CM_ASL_IRDA, + CM_ASL_1394, + CM_ASL_CAMERA, + CM_ASL_TV, + CM_ASL_GPS, + CM_ASL_DVDROM, + CM_ASL_DISPLAYSWITCH, + CM_ASL_PANELBRIGHT, + CM_ASL_BIOSFLASH, + CM_ASL_ACPIFLASH, + CM_ASL_CPUFV, + CM_ASL_CPUTEMPERATURE, + CM_ASL_FANCPU, + CM_ASL_FANCHASSIS, + CM_ASL_USBPORT1, + CM_ASL_USBPORT2, + CM_ASL_USBPORT3, + CM_ASL_MODEM, + CM_ASL_CARDREADER, + CM_ASL_LID +}; + +const char *cm_getv[] = { + "WLDG", NULL, NULL, NULL, + "CAMG", NULL, NULL, NULL, + NULL, "PBLG", NULL, NULL, + "CFVG", NULL, NULL, NULL, + "USBG", NULL, NULL, "MODG", + "CRDG", "LIDG" +}; + +const char *cm_setv[] = { + "WLDS", NULL, NULL, NULL, + "CAMS", NULL, NULL, NULL, + "SDSP", "PBLS", "HDPS", NULL, + "CFVS", NULL, NULL, NULL, + "USBG", NULL, NULL, "MODS", + "CRDS", NULL +}; + +#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." + +#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */ +#define EEEPC_EC_SC02 0x63 +#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */ +#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */ +#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */ +#define EEEPC_EC_SFB3 0xD3 + +/* + * This is the main structure, we can use it to store useful information + * about the hotk device + */ +struct eeepc_hotk { + struct acpi_device *device; /* the device we are in */ + acpi_handle handle; /* the handle of the hotk device */ + u32 cm_supported; /* the control methods supported + by this BIOS */ + uint init_flag; /* Init flags */ + u16 event_count[128]; /* count for each event */ +}; + +/* The actual device the driver binds to */ +static struct eeepc_hotk *ehotk; + +/* Platform device/driver */ +static struct platform_driver platform_driver = { + .driver = { + .name = EEEPC_HOTK_FILE, + .owner = THIS_MODULE, + } +}; + +static struct platform_device *platform_device; + +/* + * The hotkey driver declaration + */ +static int eeepc_hotk_add(struct acpi_device *device); +static int eeepc_hotk_remove(struct acpi_device *device, int type); + +static const struct acpi_device_id eeepc_device_ids[] = { + {EEEPC_HOTK_HID, 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); + +static struct acpi_driver eeepc_hotk_driver = { + .name = EEEPC_HOTK_NAME, + .class = EEEPC_HOTK_CLASS, + .ids = eeepc_device_ids, + .ops = { + .add = eeepc_hotk_add, + .remove = eeepc_hotk_remove, + }, +}; + +/* The backlight device /sys/class/backlight */ +static struct backlight_device *eeepc_backlight_device; + +/* The hwmon device */ +static struct device *eeepc_hwmon_device; + +/* + * The backlight class declaration + */ +static int read_brightness(struct backlight_device *bd); +static int update_bl_status(struct backlight_device *bd); +static struct backlight_ops eeepcbl_ops = { + .get_brightness = read_brightness, + .update_status = update_bl_status, +}; + +MODULE_AUTHOR("Corentin Chary, Eric Cooper"); +MODULE_DESCRIPTION(EEEPC_HOTK_NAME); +MODULE_LICENSE("GPL"); + +/* + * ACPI Helpers + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; + union acpi_object in_obj; + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); + return (status == AE_OK ? 0 : -1); +} + +static int read_acpi_int(acpi_handle handle, const char *method, int *val) +{ + acpi_status status; + ulong result; + + status = acpi_evaluate_integer(handle, (char *)method, NULL, &result); + if (ACPI_FAILURE(status)) { + *val = -1; + return -1; + } else { + *val = result; + return 0; + } +} + +static int set_acpi(int cm, int value) +{ + if (ehotk->cm_supported & (0x1 << cm)) { + const char *method = cm_setv[cm]; + if (method == NULL) + return -ENODEV; + if (write_acpi_int(ehotk->handle, method, value, NULL)) + printk(EEEPC_WARNING "Error writing %s\n", method); + } + return 0; +} + +static int get_acpi(int cm) +{ + int value = -1; + if ((ehotk->cm_supported & (0x1 << cm))) { + const char *method = cm_getv[cm]; + if (method == NULL) + return -ENODEV; + if (read_acpi_int(ehotk->handle, method, &value)) + printk(EEEPC_WARNING "Error reading %s\n", method); + } + return value; +} + +/* + * Backlight + */ +static int read_brightness(struct backlight_device *bd) +{ + return get_acpi(CM_ASL_PANELBRIGHT); +} + +static int set_brightness(struct backlight_device *bd, int value) +{ + value = max(0, min(15, value)); + return set_acpi(CM_ASL_PANELBRIGHT, value); +} + +static int update_bl_status(struct backlight_device *bd) +{ + return set_brightness(bd, bd->props.brightness); +} + +/* + * Sys helpers + */ +static int parse_arg(const char *buf, unsigned long count, int *val) +{ + if (!count) + return 0; + if (sscanf(buf, "%i", val) != 1) + return -EINVAL; + return count; +} + +static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + set_acpi(cm, value); + return rv; +} + +static ssize_t show_sys_acpi(int cm, char *buf) +{ + return sprintf(buf, "%d\n", get_acpi(cm)); +} + +#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ + static ssize_t show_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return show_sys_acpi(_cm, buf); \ + } \ + static ssize_t store_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + return store_sys_acpi(_cm, buf, count); \ + } \ + static struct device_attribute dev_attr_##_name = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = 0644 }, \ + .show = show_##_name, \ + .store = store_##_name, \ + } + +EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); +EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); +EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); +EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN); + +static struct attribute *platform_attributes[] = { + &dev_attr_camera.attr, + &dev_attr_cardr.attr, + &dev_attr_disp.attr, + &dev_attr_wlan.attr, + NULL +}; + +static struct attribute_group platform_attribute_group = { + .attrs = platform_attributes +}; + +/* + * Hotkey functions + */ +static int eeepc_hotk_check(void) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + int result; + + result = acpi_bus_get_status(ehotk->device); + if (result) + return result; + if (ehotk->device->status.present) { + if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, + &buffer)) { + printk(EEEPC_ERR "Hotkey initialization failed\n"); + return -ENODEV; + } else { + printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n", + ehotk->init_flag); + } + /* get control methods supported */ + if (read_acpi_int(ehotk->handle, "CMSG" + , &ehotk->cm_supported)) { + printk(EEEPC_ERR + "Get control methods supported failed\n"); + return -ENODEV; + } else { + printk(EEEPC_INFO + "Get control methods supported: 0x%x\n", + ehotk->cm_supported); + } + } else { + printk(EEEPC_ERR "Hotkey device not present, aborting\n"); + return -EINVAL; + } + return 0; +} + +static void notify_wlan(u32 *event) +{ + /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2 + will always be 0x10 */ + if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) { + const char *method = cm_getv[CM_ASL_WLAN]; + int value; + if (read_acpi_int(ehotk->handle, method, &value)) + printk(EEEPC_WARNING "Error reading %s\n", + method); + else if (value == 1) + *event = 0x11; + } +} + +static void notify_brn(void) +{ + struct backlight_device *bd = eeepc_backlight_device; + bd->props.brightness = read_brightness(bd); +} + +static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) +{ + if (!ehotk) + return; + if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag)) + notify_wlan(&event); + if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) + notify_brn(); + acpi_bus_generate_proc_event(ehotk->device, event, + ehotk->event_count[event % 128]++); +} + +static int eeepc_hotk_add(struct acpi_device *device) +{ + acpi_status status = AE_OK; + int result; + + if (!device) + return -EINVAL; + printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n"); + ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); + if (!ehotk) + return -ENOMEM; + ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; + ehotk->handle = device->handle; + strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); + acpi_driver_data(device) = ehotk; + ehotk->device = device; + result = eeepc_hotk_check(); + if (result) + goto end; + status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, + eeepc_hotk_notify, ehotk); + if (ACPI_FAILURE(status)) + printk(EEEPC_ERR "Error installing notify handler\n"); + end: + if (result) { + kfree(ehotk); + ehotk = NULL; + } + return result; +} + +static int eeepc_hotk_remove(struct acpi_device *device, int type) +{ + acpi_status status = 0; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, + eeepc_hotk_notify); + if (ACPI_FAILURE(status)) + printk(EEEPC_ERR "Error removing notify handler\n"); + kfree(ehotk); + return 0; +} + +/* + * Hwmon + */ +static int eeepc_get_fan_pwm(void) +{ + int value = 0; + + read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value); + return (value); +} + +static void eeepc_set_fan_pwm(int value) +{ + value = SENSORS_LIMIT(value, 0, 100); + ec_write(EEEPC_EC_SC02, value); +} + +static int eeepc_get_fan_rpm(void) +{ + int high = 0; + int low = 0; + + read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high); + read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low); + return (high << 8 | low); +} + +static int eeepc_get_fan_ctrl(void) +{ + int value = 0; + + read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); + return ((value & 0x02 ? 1 : 0)); +} + +static void eeepc_set_fan_ctrl(int manual) +{ + int value = 0; + + read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); + if (manual) + value |= 0x02; + else + value &= ~0x02; + ec_write(EEEPC_EC_SFB3, value); +} + +static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + set(value); + return rv; +} + +static ssize_t show_sys_hwmon(int (*get)(void), char *buf) +{ + return sprintf(buf, "%d\n", get()); +} + +#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ + static ssize_t show_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return show_sys_hwmon(_set, buf); \ + } \ + static ssize_t store_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + return store_sys_hwmon(_get, buf, count); \ + } \ + static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); + +EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL); +EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, + eeepc_get_fan_pwm, eeepc_set_fan_pwm); +EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + eeepc_get_fan_ctrl, eeepc_set_fan_ctrl); + +static struct attribute *hwmon_attributes[] = { + &sensor_dev_attr_fan1_pwm.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + NULL +}; + +static struct attribute_group hwmon_attribute_group = { + .attrs = hwmon_attributes +}; + +/* + * exit/init + */ +static void eeepc_backlight_exit(void) +{ + if (eeepc_backlight_device) + backlight_device_unregister(eeepc_backlight_device); + eeepc_backlight_device = NULL; +} + +static void eeepc_hwmon_exit(void) +{ + struct device *hwmon; + + hwmon = eeepc_hwmon_device; + if (!hwmon) + return ; + hwmon_device_unregister(hwmon); + sysfs_remove_group(&hwmon->kobj, + &hwmon_attribute_group); + eeepc_hwmon_device = NULL; +} + +static void __exit eeepc_laptop_exit(void) +{ + eeepc_backlight_exit(); + eeepc_hwmon_exit(); + acpi_bus_unregister_driver(&eeepc_hotk_driver); + sysfs_remove_group(&platform_device->dev.kobj, + &platform_attribute_group); + platform_device_unregister(platform_device); + platform_driver_unregister(&platform_driver); +} + +static int eeepc_backlight_init(struct device *dev) +{ + struct backlight_device *bd; + + bd = backlight_device_register(EEEPC_HOTK_FILE, dev, + NULL, &eeepcbl_ops); + if (IS_ERR(bd)) { + printk(EEEPC_ERR + "Could not register eeepc backlight device\n"); + eeepc_backlight_device = NULL; + return PTR_ERR(bd); + } + eeepc_backlight_device = bd; + bd->props.max_brightness = 15; + bd->props.brightness = read_brightness(NULL); + bd->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bd); + return 0; +} + +static int eeepc_hwmon_init(struct device *dev) +{ + struct device *hwmon; + int result; + + hwmon = hwmon_device_register(dev); + if (IS_ERR(hwmon)) { + printk(EEEPC_ERR + "Could not register eeepc hwmon device\n"); + eeepc_hwmon_device = NULL; + return PTR_ERR(hwmon); + } + eeepc_hwmon_device = hwmon; + result = sysfs_create_group(&hwmon->kobj, + &hwmon_attribute_group); + if (result) + eeepc_hwmon_exit(); + return result; +} + +static int __init eeepc_laptop_init(void) +{ + struct device *dev; + int result; + + if (acpi_disabled) + return -ENODEV; + result = acpi_bus_register_driver(&eeepc_hotk_driver); + if (result < 0) + return result; + if (!ehotk) { + acpi_bus_unregister_driver(&eeepc_hotk_driver); + return -ENODEV; + } + dev = acpi_get_physical_device(ehotk->device->handle); + result = eeepc_backlight_init(dev); + if (result) + goto fail_backlight; + result = eeepc_hwmon_init(dev); + if (result) + goto fail_hwmon; + /* Register platform stuff */ + result = platform_driver_register(&platform_driver); + if (result) + goto fail_platform_driver; + platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1); + if (!platform_device) { + result = -ENOMEM; + goto fail_platform_device1; + } + result = platform_device_add(platform_device); + if (result) + goto fail_platform_device2; + result = sysfs_create_group(&platform_device->dev.kobj, + &platform_attribute_group); + if (result) + goto fail_sysfs; + return 0; +fail_sysfs: + platform_device_del(platform_device); +fail_platform_device2: + platform_device_put(platform_device); +fail_platform_device1: + platform_driver_unregister(&platform_driver); +fail_platform_driver: + eeepc_hwmon_exit(); +fail_hwmon: + eeepc_backlight_exit(); +fail_backlight: + return result; +} + +module_init(eeepc_laptop_init); +module_exit(eeepc_laptop_exit); diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 302e92418bbe..ff51ab67231c 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -210,13 +210,10 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) return ret; } - proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root); + proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate); if (!proc_de) { printk(KERN_WARNING "sky_cpustate: " "Unable to create proc entry\n"); - } else { - proc_de->proc_fops = &proc_cpustate; - proc_de->owner = THIS_MODULE; } printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 2fa36f7a6eb3..08e26beefe64 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -102,22 +102,17 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_ERR "sky_nexus: Could not map slot id\n"); } - hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); + hdpu_slot_id = proc_create("sky_slot_id", 0666, NULL, &proc_slot_id); if (!hdpu_slot_id) { printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_slot_id\n"); - } else { - hdpu_slot_id->proc_fops = &proc_slot_id; - hdpu_slot_id->owner = THIS_MODULE; } - hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); - if (!hdpu_chassis_id) { + hdpu_chassis_id = proc_create("sky_chassis_id", 0666, NULL, + &proc_chassis_id); + if (!hdpu_chassis_id) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_chassis_id\n"); - } else { - hdpu_chassis_id->proc_fops = &proc_chassis_id; - hdpu_chassis_id->owner = THIS_MODULE; } return 0; @@ -128,8 +123,8 @@ static int hdpu_nexus_remove(struct platform_device *pdev) slot_id = -1; chassis_id = -1; - remove_proc_entry("sky_slot_id", &proc_root); - remove_proc_entry("sky_chassis_id", &proc_root); + remove_proc_entry("sky_slot_id", NULL); + remove_proc_entry("sky_chassis_id", NULL); hdpu_slot_id = 0; hdpu_chassis_id = 0; diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 1a0e7978226a..276d3fb68094 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -96,7 +96,7 @@ static inline void do_exec_command(struct service_processor *sp) { char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); if (ibmasm_send_i2o_message(sp)) { sp->current_command->status = IBMASM_CMD_FAILED; @@ -119,7 +119,7 @@ void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) unsigned long flags; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); @@ -139,7 +139,7 @@ static void exec_next_command(struct service_processor *sp) unsigned long flags; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); sp->current_command = dequeue_command(sp); diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index 3036e785b3e4..1bc4306572a4 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -75,9 +75,9 @@ void ibmasm_heartbeat_exit(struct service_processor *sp) { char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL); - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); suspend_heartbeats = 1; command_put(sp->heartbeat); } @@ -88,7 +88,7 @@ void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size struct dot_command_header *header = (struct dot_command_header *)cmd->buffer; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); if (suspend_heartbeats) return; diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c index 0c0bb3093e07..80a136352408 100644 --- a/drivers/misc/intel_menlow.c +++ b/drivers/misc/intel_menlow.c @@ -175,19 +175,17 @@ static int intel_menlow_memory_add(struct acpi_device *device) goto end; } - if (cdev) { - acpi_driver_data(device) = cdev; - result = sysfs_create_link(&device->dev.kobj, - &cdev->device.kobj, "thermal_cooling"); - if (result) - goto unregister; - - result = sysfs_create_link(&cdev->device.kobj, - &device->dev.kobj, "device"); - if (result) { - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - goto unregister; - } + acpi_driver_data(device) = cdev; + result = sysfs_create_link(&device->dev.kobj, + &cdev->device.kobj, "thermal_cooling"); + if (result) + goto unregister; + + result = sysfs_create_link(&cdev->device.kobj, + &device->dev.kobj, "device"); + if (result) { + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); + goto unregister; } end: diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 05172d2613d6..6f76573e7c8a 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -75,7 +75,7 @@ ioc4_register_submodule(struct ioc4_submodule *is) printk(KERN_WARNING "%s: IOC4 submodule %s probe failed " "for pci_dev %s", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -102,7 +102,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) printk(KERN_WARNING "%s: IOC4 submodule %s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -282,7 +282,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if ((ret = pci_enable_device(pdev))) { printk(KERN_WARNING "%s: Failed to enable IOC4 device for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); goto out; } pci_set_master(pdev); @@ -292,7 +292,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (!idd) { printk(KERN_WARNING "%s: Failed to allocate IOC4 data for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_idd; } @@ -307,7 +307,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to find IOC4 misc resource " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_pci; } @@ -316,7 +316,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to request IOC4 misc region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_pci; } @@ -326,7 +326,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to remap IOC4 misc region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_misc_region; } @@ -372,7 +372,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: IOC4 submodule 0x%s probe failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -406,7 +406,7 @@ ioc4_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: IOC4 submodule 0x%s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -418,7 +418,7 @@ ioc4_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: Unable to get IOC4 misc mapping for pci_dev %s. " "Device removal may be incomplete.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); } release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 6d6286c4eeac..30a1af857c7a 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/misc/phantom.c b/drivers/misc/phantom.c index 7fa61e907e1c..71d1c84e2fa8 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -12,6 +12,7 @@ * or alternatively, you might use OpenHaptics provided by Sensable. */ +#include <linux/compat.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> @@ -91,11 +92,8 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, unsigned long flags; unsigned int i; - if (_IOC_TYPE(cmd) != PH_IOC_MAGIC || - _IOC_NR(cmd) > PH_IOC_MAXNR) - return -ENOTTY; - switch (cmd) { + case PHN_SETREG: case PHN_SET_REG: if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -126,6 +124,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, phantom_status(dev, dev->status & ~PHB_RUNNING); spin_unlock_irqrestore(&dev->regs_lock, flags); break; + case PHN_SETREGS: case PHN_SET_REGS: if (copy_from_user(&rs, argp, sizeof(rs))) return -EFAULT; @@ -143,6 +142,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, } spin_unlock_irqrestore(&dev->regs_lock, flags); break; + case PHN_GETREG: case PHN_GET_REG: if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -155,6 +155,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, if (copy_to_user(argp, &r, sizeof(r))) return -EFAULT; break; + case PHN_GETREGS: case PHN_GET_REGS: { u32 m; @@ -168,6 +169,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, for (i = 0; i < m; i++) if (rs.mask & BIT(i)) rs.values[i] = ioread32(dev->iaddr + i); + atomic_set(&dev->counter, 0); spin_unlock_irqrestore(&dev->regs_lock, flags); if (copy_to_user(argp, &rs, sizeof(rs))) @@ -191,6 +193,20 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, return 0; } +#ifdef CONFIG_COMPAT +static long phantom_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) { + cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT); + cmd |= sizeof(void *) << _IOC_SIZESHIFT; + } + return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#else +#define phantom_compat_ioctl NULL +#endif + static int phantom_open(struct inode *inode, struct file *file) { struct phantom_device *dev = container_of(inode->i_cdev, @@ -239,11 +255,12 @@ static unsigned int phantom_poll(struct file *file, poll_table *wait) pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter)); poll_wait(file, &dev->wait, wait); - if (atomic_read(&dev->counter)) { + + if (!(dev->status & PHB_RUNNING)) + mask = POLLERR; + else if (atomic_read(&dev->counter)) mask = POLLIN | POLLRDNORM; - atomic_dec(&dev->counter); - } else if ((dev->status & PHB_RUNNING) == 0) - mask = POLLIN | POLLRDNORM | POLLERR; + pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter)); return mask; @@ -253,6 +270,7 @@ static struct file_operations phantom_file_ops = { .open = phantom_open, .release = phantom_release, .unlocked_ioctl = phantom_ioctl, + .compat_ioctl = phantom_compat_ioctl, .poll = phantom_poll, }; diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 27e200ec5826..acd3fd4285d7 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -211,7 +211,7 @@ xpc_rsvd_page_init(void) */ amos_page = xpc_vars->amos_page; if (amos_page == NULL) { - amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0)); + amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); if (amos_page == NULL) { dev_err(xpc_part, "can't allocate page of AMOs\n"); return NULL; @@ -230,7 +230,7 @@ xpc_rsvd_page_init(void) dev_err(xpc_part, "can't change memory " "protections\n"); uncached_free_page(__IA64_UNCACHED_OFFSET | - TO_PHYS((u64)amos_page)); + TO_PHYS((u64)amos_page), 1); return NULL; } } diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 02ff3d19b1cc..00e48e2a9c11 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -961,7 +961,7 @@ static int sony_nc_resume(struct acpi_device *device) ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, item->value, NULL); if (ret < 0) { - printk("%s: %d\n", __FUNCTION__, ret); + printk("%s: %d\n", __func__, ret); break; } } @@ -1453,7 +1453,7 @@ static struct sonypi_eventtypes type4_events[] = { udelay(1); \ if (!n) \ dprintk("command failed at %s : %s (line %d)\n", \ - __FILE__, __FUNCTION__, __LINE__); \ + __FILE__, __func__, __LINE__); \ } static u8 sony_pic_call1(u8 dev) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 6cb781262f94..3f28f6eabdbf 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define TPACPI_VERSION "0.19" +#define TPACPI_VERSION "0.20" #define TPACPI_SYSFS_VERSION 0x020200 /* @@ -67,6 +67,7 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/input.h> +#include <linux/leds.h> #include <asm/uaccess.h> #include <linux/dmi.h> @@ -85,6 +86,8 @@ #define TP_CMOS_VOLUME_MUTE 2 #define TP_CMOS_BRIGHTNESS_UP 4 #define TP_CMOS_BRIGHTNESS_DOWN 5 +#define TP_CMOS_THINKLIGHT_ON 12 +#define TP_CMOS_THINKLIGHT_OFF 13 /* NVRAM Addresses */ enum tp_nvram_addr { @@ -133,8 +136,12 @@ enum { #define TPACPI_PROC_DIR "ibm" #define TPACPI_ACPI_EVENT_PREFIX "ibm" #define TPACPI_DRVR_NAME TPACPI_FILE +#define TPACPI_DRVR_SHORTNAME "tpacpi" #define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon" +#define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd" +#define TPACPI_WORKQUEUE_NAME "ktpacpid" + #define TPACPI_MAX_ACPI_ARGS 3 /* Debugging */ @@ -225,6 +232,7 @@ static struct { u32 light:1; u32 light_status:1; u32 bright_16levels:1; + u32 bright_acpimode:1; u32 wan:1; u32 fan_ctrl_status_undef:1; u32 input_device_registered:1; @@ -236,6 +244,11 @@ static struct { u32 hotkey_poll_active:1; } tp_features; +static struct { + u16 hotkey_mask_ff:1; + u16 bright_cmos_ec_unsync:1; +} tp_warned; + struct thinkpad_id_data { unsigned int vendor; /* ThinkPad vendor: * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ @@ -246,7 +259,8 @@ struct thinkpad_id_data { u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ u16 ec_model; - char *model_str; + char *model_str; /* ThinkPad T43 */ + char *nummodel_str; /* 9384A9C for a 9384-A9C model */ }; static struct thinkpad_id_data thinkpad_id; @@ -259,6 +273,16 @@ static enum { static int experimental; static u32 dbg_level; +static struct workqueue_struct *tpacpi_wq; + +/* Special LED class that can defer work */ +struct tpacpi_led_classdev { + struct led_classdev led_classdev; + struct work_struct work; + enum led_brightness new_brightness; + unsigned int led; +}; + /**************************************************************************** **************************************************************************** * @@ -807,6 +831,80 @@ static int parse_strtoul(const char *buf, return 0; } +static int __init tpacpi_query_bcl_levels(acpi_handle handle) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + int rc; + + if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { + obj = (union acpi_object *)buffer.pointer; + if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { + printk(TPACPI_ERR "Unknown _BCL data, " + "please report this to %s\n", TPACPI_MAIL); + rc = 0; + } else { + rc = obj->package.count; + } + } else { + return 0; + } + + kfree(buffer.pointer); + return rc; +} + +static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, + u32 lvl, void *context, void **rv) +{ + char name[ACPI_PATH_SEGMENT_LENGTH]; + struct acpi_buffer buffer = { sizeof(name), &name }; + + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && + !strncmp("_BCL", name, sizeof(name) - 1)) { + BUG_ON(!rv || !*rv); + **(int **)rv = tpacpi_query_bcl_levels(handle); + return AE_CTRL_TERMINATE; + } else { + return AE_OK; + } +} + +/* + * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map + */ +static int __init tpacpi_check_std_acpi_brightness_support(void) +{ + int status; + int bcl_levels = 0; + void *bcl_ptr = &bcl_levels; + + if (!vid_handle) { + TPACPI_ACPIHANDLE_INIT(vid); + } + if (!vid_handle) + return 0; + + /* + * Search for a _BCL method, and execute it. This is safe on all + * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista + * BIOS in ACPI backlight control mode. We do NOT have to care + * about calling the _BCL method in an enabled video device, any + * will do for our purposes. + */ + + status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, + tpacpi_acpi_walk_find_bcl, NULL, + &bcl_ptr); + + if (ACPI_SUCCESS(status) && bcl_levels > 2) { + tp_features.bright_acpimode = 1; + return (bcl_levels - 2); + } + + return 0; +} + /************************************************************************* * thinkpad-acpi driver attributes */ @@ -909,12 +1007,14 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) thinkpad_id.ec_version_str : "unknown"); if (thinkpad_id.vendor && thinkpad_id.model_str) - printk(TPACPI_INFO "%s %s\n", + printk(TPACPI_INFO "%s %s, model %s\n", (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? "IBM" : ((thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) ? "Lenovo" : "Unknown vendor"), - thinkpad_id.model_str); + thinkpad_id.model_str, + (thinkpad_id.nummodel_str) ? + thinkpad_id.nummodel_str : "unknown"); return 0; } @@ -1107,6 +1207,19 @@ static int hotkey_mask_set(u32 mask) int rc = 0; if (tp_features.hotkey_mask) { + if (!tp_warned.hotkey_mask_ff && + (mask == 0xffff || mask == 0xffffff || + mask == 0xffffffff)) { + tp_warned.hotkey_mask_ff = 1; + printk(TPACPI_NOTICE + "setting the hotkey mask to 0x%08x is likely " + "not the best way to go about it\n", mask); + printk(TPACPI_NOTICE + "please consider using the driver defaults, " + "and refer to up-to-date thinkpad-acpi " + "documentation\n"); + } + HOTKEY_CONFIG_CRITICAL_START for (i = 0; i < 32; i++) { u32 m = 1 << i; @@ -1427,8 +1540,7 @@ static void hotkey_poll_setup(int may_warn) (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, - NULL, - TPACPI_FILE "d"); + NULL, TPACPI_NVRAM_KTHREAD_NAME); if (IS_ERR(tpacpi_hotkey_task)) { tpacpi_hotkey_task = NULL; printk(TPACPI_ERR @@ -1887,6 +1999,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + /* These either have to go through ACPI video, or + * act like in the IBM ThinkPads, so don't ever + * enable them by default */ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */ @@ -2091,6 +2206,32 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); } + /* Do not issue duplicate brightness change events to + * userspace */ + if (!tp_features.bright_acpimode) + /* update bright_acpimode... */ + tpacpi_check_std_acpi_brightness_support(); + + if (tp_features.bright_acpimode) { + printk(TPACPI_INFO + "This ThinkPad has standard ACPI backlight " + "brightness control, supported by the ACPI " + "video driver\n"); + printk(TPACPI_NOTICE + "Disabling thinkpad-acpi brightness events " + "by default...\n"); + + /* The hotkey_reserved_mask change below is not + * necessary while the keys are at KEY_RESERVED in the + * default map, but better safe than sorry, leave it + * here as a marker of what we have to do, especially + * when we finally become able to set this at runtime + * on response to X.org requests */ + hotkey_reserved_mask |= + (1 << TP_ACPI_HOTKEYSCAN_FNHOME) + | (1 << TP_ACPI_HOTKEYSCAN_FNEND); + } + dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); res = hotkey_status_set(1); @@ -3110,13 +3251,82 @@ static struct ibm_struct video_driver_data = { TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */ +static int light_get_status(void) +{ + int status = 0; + + if (tp_features.light_status) { + if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) + return -EIO; + return (!!status); + } + + return -ENXIO; +} + +static int light_set_status(int status) +{ + int rc; + + if (tp_features.light) { + if (cmos_handle) { + rc = acpi_evalf(cmos_handle, NULL, NULL, "vd", + (status)? + TP_CMOS_THINKLIGHT_ON : + TP_CMOS_THINKLIGHT_OFF); + } else { + rc = acpi_evalf(lght_handle, NULL, NULL, "vd", + (status)? 1 : 0); + } + return (rc)? 0 : -EIO; + } + + return -ENXIO; +} + +static void light_set_status_worker(struct work_struct *work) +{ + struct tpacpi_led_classdev *data = + container_of(work, struct tpacpi_led_classdev, work); + + if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) + light_set_status((data->new_brightness != LED_OFF)); +} + +static void light_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct tpacpi_led_classdev *data = + container_of(led_cdev, + struct tpacpi_led_classdev, + led_classdev); + data->new_brightness = brightness; + queue_work(tpacpi_wq, &data->work); +} + +static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) +{ + return (light_get_status() == 1)? LED_FULL : LED_OFF; +} + +static struct tpacpi_led_classdev tpacpi_led_thinklight = { + .led_classdev = { + .name = "tpacpi::thinklight", + .brightness_set = &light_sysfs_set, + .brightness_get = &light_sysfs_get, + } +}; + static int __init light_init(struct ibm_init_struct *iibm) { + int rc = 0; + vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); TPACPI_ACPIHANDLE_INIT(ledb); TPACPI_ACPIHANDLE_INIT(lght); TPACPI_ACPIHANDLE_INIT(cmos); + INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; @@ -3130,13 +3340,31 @@ static int __init light_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", str_supported(tp_features.light)); - return (tp_features.light)? 0 : 1; + if (tp_features.light) { + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_led_thinklight.led_classdev); + } + + if (rc < 0) { + tp_features.light = 0; + tp_features.light_status = 0; + } else { + rc = (tp_features.light)? 0 : 1; + } + return rc; +} + +static void light_exit(void) +{ + led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); + if (work_pending(&tpacpi_led_thinklight.work)) + flush_workqueue(tpacpi_wq); } static int light_read(char *p) { int len = 0; - int status = 0; + int status; if (!tp_features.light) { len += sprintf(p + len, "status:\t\tnot supported\n"); @@ -3144,8 +3372,9 @@ static int light_read(char *p) len += sprintf(p + len, "status:\t\tunknown\n"); len += sprintf(p + len, "commands:\ton, off\n"); } else { - if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) - return -EIO; + status = light_get_status(); + if (status < 0) + return status; len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); len += sprintf(p + len, "commands:\ton, off\n"); } @@ -3155,37 +3384,29 @@ static int light_read(char *p) static int light_write(char *buf) { - int cmos_cmd, lght_cmd; char *cmd; - int success; + int newstatus = 0; if (!tp_features.light) return -ENODEV; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "on") == 0) { - cmos_cmd = 0x0c; - lght_cmd = 1; + newstatus = 1; } else if (strlencmp(cmd, "off") == 0) { - cmos_cmd = 0x0d; - lght_cmd = 0; + newstatus = 0; } else return -EINVAL; - - success = cmos_handle ? - acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) : - acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd); - if (!success) - return -EIO; } - return 0; + return light_set_status(newstatus); } static struct ibm_struct light_driver_data = { .name = "light", .read = light_read, .write = light_write, + .exit = light_exit, }; /************************************************************************* @@ -3583,6 +3804,12 @@ enum { /* For TPACPI_LED_OLD */ TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ }; +enum led_status_t { + TPACPI_LED_OFF = 0, + TPACPI_LED_ON, + TPACPI_LED_BLINK, +}; + static enum led_access_mode led_supported; TPACPI_HANDLE(led, ec, "SLED", /* 570 */ @@ -3591,8 +3818,174 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */ "LED", /* all others */ ); /* R30, R31 */ +#define TPACPI_LED_NUMLEDS 8 +static struct tpacpi_led_classdev *tpacpi_leds; +static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; +static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = { + /* there's a limit of 19 chars + NULL before 2.6.26 */ + "tpacpi::power", + "tpacpi:orange:batt", + "tpacpi:green:batt", + "tpacpi::dock_active", + "tpacpi::bay_active", + "tpacpi::dock_batt", + "tpacpi::unknown_led", + "tpacpi::standby", +}; + +static int led_get_status(unsigned int led) +{ + int status; + enum led_status_t led_s; + + switch (led_supported) { + case TPACPI_LED_570: + if (!acpi_evalf(ec_handle, + &status, "GLED", "dd", 1 << led)) + return -EIO; + led_s = (status == 0)? + TPACPI_LED_OFF : + ((status == 1)? + TPACPI_LED_ON : + TPACPI_LED_BLINK); + tpacpi_led_state_cache[led] = led_s; + return led_s; + default: + return -ENXIO; + } + + /* not reached */ +} + +static int led_set_status(unsigned int led, enum led_status_t ledstatus) +{ + /* off, on, blink. Index is led_status_t */ + static const int const led_sled_arg1[] = { 0, 1, 3 }; + static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ + static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ + static const int const led_led_arg1[] = { 0, 0x80, 0xc0 }; + + int rc = 0; + + switch (led_supported) { + case TPACPI_LED_570: + /* 570 */ + led = 1 << led; + if (!acpi_evalf(led_handle, NULL, NULL, "vdd", + led, led_sled_arg1[ledstatus])) + rc = -EIO; + break; + case TPACPI_LED_OLD: + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ + led = 1 << led; + rc = ec_write(TPACPI_LED_EC_HLMS, led); + if (rc >= 0) + rc = ec_write(TPACPI_LED_EC_HLBL, + led * led_exp_hlbl[ledstatus]); + if (rc >= 0) + rc = ec_write(TPACPI_LED_EC_HLCL, + led * led_exp_hlcl[ledstatus]); + break; + case TPACPI_LED_NEW: + /* all others */ + if (!acpi_evalf(led_handle, NULL, NULL, "vdd", + led, led_led_arg1[ledstatus])) + rc = -EIO; + break; + default: + rc = -ENXIO; + } + + if (!rc) + tpacpi_led_state_cache[led] = ledstatus; + + return rc; +} + +static void led_sysfs_set_status(unsigned int led, + enum led_brightness brightness) +{ + led_set_status(led, + (brightness == LED_OFF) ? + TPACPI_LED_OFF : + (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ? + TPACPI_LED_BLINK : TPACPI_LED_ON); +} + +static void led_set_status_worker(struct work_struct *work) +{ + struct tpacpi_led_classdev *data = + container_of(work, struct tpacpi_led_classdev, work); + + if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) + led_sysfs_set_status(data->led, data->new_brightness); +} + +static void led_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct tpacpi_led_classdev *data = container_of(led_cdev, + struct tpacpi_led_classdev, led_classdev); + + data->new_brightness = brightness; + queue_work(tpacpi_wq, &data->work); +} + +static int led_sysfs_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, unsigned long *delay_off) +{ + struct tpacpi_led_classdev *data = container_of(led_cdev, + struct tpacpi_led_classdev, led_classdev); + + /* Can we choose the flash rate? */ + if (*delay_on == 0 && *delay_off == 0) { + /* yes. set them to the hardware blink rate (1 Hz) */ + *delay_on = 500; /* ms */ + *delay_off = 500; /* ms */ + } else if ((*delay_on != 500) || (*delay_off != 500)) + return -EINVAL; + + data->new_brightness = TPACPI_LED_BLINK; + queue_work(tpacpi_wq, &data->work); + + return 0; +} + +static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev) +{ + int rc; + + struct tpacpi_led_classdev *data = container_of(led_cdev, + struct tpacpi_led_classdev, led_classdev); + + rc = led_get_status(data->led); + + if (rc == TPACPI_LED_OFF || rc < 0) + rc = LED_OFF; /* no error handling in led class :( */ + else + rc = LED_FULL; + + return rc; +} + +static void led_exit(void) +{ + unsigned int i; + + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { + if (tpacpi_leds[i].led_classdev.name) + led_classdev_unregister(&tpacpi_leds[i].led_classdev); + } + + kfree(tpacpi_leds); + tpacpi_leds = NULL; +} + static int __init led_init(struct ibm_init_struct *iibm) { + unsigned int i; + int rc; + vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); TPACPI_ACPIHANDLE_INIT(led); @@ -3613,10 +4006,41 @@ static int __init led_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", str_supported(led_supported), led_supported); + tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, + GFP_KERNEL); + if (!tpacpi_leds) { + printk(TPACPI_ERR "Out of memory for LED data\n"); + return -ENOMEM; + } + + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { + tpacpi_leds[i].led = i; + + tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set; + tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set; + if (led_supported == TPACPI_LED_570) + tpacpi_leds[i].led_classdev.brightness_get = + &led_sysfs_get; + + tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i]; + + INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker); + + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_leds[i].led_classdev); + if (rc < 0) { + tpacpi_leds[i].led_classdev.name = NULL; + led_exit(); + return rc; + } + } + return (led_supported != TPACPI_LED_NONE)? 0 : 1; } -#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking")) +#define str_led_status(s) \ + ((s) == TPACPI_LED_OFF ? "off" : \ + ((s) == TPACPI_LED_ON ? "on" : "blinking")) static int led_read(char *p) { @@ -3632,11 +4056,11 @@ static int led_read(char *p) /* 570 */ int i, status; for (i = 0; i < 8; i++) { - if (!acpi_evalf(ec_handle, - &status, "GLED", "dd", 1 << i)) + status = led_get_status(i); + if (status < 0) return -EIO; len += sprintf(p + len, "%d:\t\t%s\n", - i, led_status(status)); + i, str_led_status(status)); } } @@ -3646,16 +4070,11 @@ static int led_read(char *p) return len; } -/* off, on, blink */ -static const int led_sled_arg1[] = { 0, 1, 3 }; -static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ -static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ -static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; - static int led_write(char *buf) { char *cmd; - int led, ind, ret; + int led, rc; + enum led_status_t s; if (!led_supported) return -ENODEV; @@ -3665,38 +4084,18 @@ static int led_write(char *buf) return -EINVAL; if (strstr(cmd, "off")) { - ind = 0; + s = TPACPI_LED_OFF; } else if (strstr(cmd, "on")) { - ind = 1; + s = TPACPI_LED_ON; } else if (strstr(cmd, "blink")) { - ind = 2; - } else - return -EINVAL; - - if (led_supported == TPACPI_LED_570) { - /* 570 */ - led = 1 << led; - if (!acpi_evalf(led_handle, NULL, NULL, "vdd", - led, led_sled_arg1[ind])) - return -EIO; - } else if (led_supported == TPACPI_LED_OLD) { - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ - led = 1 << led; - ret = ec_write(TPACPI_LED_EC_HLMS, led); - if (ret >= 0) - ret = ec_write(TPACPI_LED_EC_HLBL, - led * led_exp_hlbl[ind]); - if (ret >= 0) - ret = ec_write(TPACPI_LED_EC_HLCL, - led * led_exp_hlcl[ind]); - if (ret < 0) - return ret; + s = TPACPI_LED_BLINK; } else { - /* all others */ - if (!acpi_evalf(led_handle, NULL, NULL, "vdd", - led, led_led_arg1[ind])) - return -EIO; + return -EINVAL; } + + rc = led_set_status(led, s); + if (rc < 0) + return rc; } return 0; @@ -3706,6 +4105,7 @@ static struct ibm_struct led_driver_data = { .name = "led", .read = led_read, .write = led_write, + .exit = led_exit, }; /************************************************************************* @@ -4170,8 +4570,16 @@ static struct ibm_struct ecdump_driver_data = { #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" +enum { + TP_EC_BACKLIGHT = 0x31, + + /* TP_EC_BACKLIGHT bitmasks */ + TP_EC_BACKLIGHT_LVLMSK = 0x1F, + TP_EC_BACKLIGHT_CMDMSK = 0xE0, + TP_EC_BACKLIGHT_MAPSW = 0x20, +}; + static struct backlight_device *ibm_backlight_device; -static int brightness_offset = 0x31; static int brightness_mode; static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ @@ -4180,16 +4588,24 @@ static struct mutex brightness_mutex; /* * ThinkPads can read brightness from two places: EC 0x31, or * CMOS NVRAM byte 0x5E, bits 0-3. + * + * EC 0x31 has the following layout + * Bit 7: unknown function + * Bit 6: unknown function + * Bit 5: Z: honour scale changes, NZ: ignore scale changes + * Bit 4: must be set to zero to avoid problems + * Bit 3-0: backlight brightness level + * + * brightness_get_raw returns status data in the EC 0x31 layout */ -static int brightness_get(struct backlight_device *bd) +static int brightness_get_raw(int *status) { u8 lec = 0, lcmos = 0, level = 0; if (brightness_mode & 1) { - if (!acpi_ec_read(brightness_offset, &lec)) + if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec)) return -EIO; - lec &= (tp_features.bright_16levels)? 0x0f : 0x07; - level = lec; + level = lec & TP_EC_BACKLIGHT_LVLMSK; }; if (brightness_mode & 2) { lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) @@ -4199,16 +4615,27 @@ static int brightness_get(struct backlight_device *bd) level = lcmos; } - if (brightness_mode == 3 && lec != lcmos) { - printk(TPACPI_ERR - "CMOS NVRAM (%u) and EC (%u) do not agree " - "on display brightness level\n", - (unsigned int) lcmos, - (unsigned int) lec); - return -EIO; + if (brightness_mode == 3) { + *status = lec; /* Prefer EC, CMOS is just a backing store */ + lec &= TP_EC_BACKLIGHT_LVLMSK; + if (lec == lcmos) + tp_warned.bright_cmos_ec_unsync = 0; + else { + if (!tp_warned.bright_cmos_ec_unsync) { + printk(TPACPI_ERR + "CMOS NVRAM (%u) and EC (%u) do not " + "agree on display brightness level\n", + (unsigned int) lcmos, + (unsigned int) lec); + tp_warned.bright_cmos_ec_unsync = 1; + } + return -EIO; + } + } else { + *status = level; } - return level; + return 0; } /* May return EINTR which can always be mapped to ERESTARTSYS */ @@ -4216,19 +4643,22 @@ static int brightness_set(int value) { int cmos_cmd, inc, i, res; int current_value; + int command_bits; - if (value > ((tp_features.bright_16levels)? 15 : 7)) + if (value > ((tp_features.bright_16levels)? 15 : 7) || + value < 0) return -EINVAL; res = mutex_lock_interruptible(&brightness_mutex); if (res < 0) return res; - current_value = brightness_get(NULL); - if (current_value < 0) { - res = current_value; + res = brightness_get_raw(¤t_value); + if (res < 0) goto errout; - } + + command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK; + current_value &= TP_EC_BACKLIGHT_LVLMSK; cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : @@ -4243,7 +4673,8 @@ static int brightness_set(int value) goto errout; } if ((brightness_mode & 1) && - !acpi_ec_write(brightness_offset, i + inc)) { + !acpi_ec_write(TP_EC_BACKLIGHT, + (i + inc) | command_bits)) { res = -EIO; goto errout;; } @@ -4266,106 +4697,23 @@ static int brightness_update_status(struct backlight_device *bd) bd->props.brightness : 0); } -static struct backlight_ops ibm_backlight_data = { - .get_brightness = brightness_get, - .update_status = brightness_update_status, -}; - -/* --------------------------------------------------------------------- */ - -static int __init tpacpi_query_bcll_levels(acpi_handle handle) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - int rc; - - if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { - obj = (union acpi_object *)buffer.pointer; - if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { - printk(TPACPI_ERR "Unknown BCLL data, " - "please report this to %s\n", TPACPI_MAIL); - rc = 0; - } else { - rc = obj->package.count; - } - } else { - return 0; - } - - kfree(buffer.pointer); - return rc; -} - -static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("BCLL", name, sizeof(name) - 1)) { - if (tpacpi_query_bcll_levels(handle) == 16) { - *rv = handle; - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } - } else { - return AE_OK; - } -} - -static int __init brightness_check_levels(void) +static int brightness_get(struct backlight_device *bd) { - int status; - void *found_node = NULL; + int status, res; - if (!vid_handle) { - TPACPI_ACPIHANDLE_INIT(vid); - } - if (!vid_handle) - return 0; - - /* Search for a BCLL package with 16 levels */ - status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3, - brightness_find_bcll, NULL, - &found_node); - - return (ACPI_SUCCESS(status) && found_node != NULL); -} - -static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; + res = brightness_get_raw(&status); + if (res < 0) + return 0; /* FIXME: teach backlight about error handling */ - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("_BCL", name, sizeof(name) - 1)) { - *rv = handle; - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } + return status & TP_EC_BACKLIGHT_LVLMSK; } -static int __init brightness_check_std_acpi_support(void) -{ - int status; - void *found_node = NULL; - - if (!vid_handle) { - TPACPI_ACPIHANDLE_INIT(vid); - } - if (!vid_handle) - return 0; - - /* Search for a _BCL method, but don't execute it */ - status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - brightness_find_bcl, NULL, &found_node); +static struct backlight_ops ibm_backlight_data = { + .get_brightness = brightness_get, + .update_status = brightness_update_status, +}; - return (ACPI_SUCCESS(status) && found_node != NULL); -} +/* --------------------------------------------------------------------- */ static int __init brightness_init(struct ibm_init_struct *iibm) { @@ -4375,13 +4723,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm) mutex_init(&brightness_mutex); - if (!brightness_enable) { - dbg_printk(TPACPI_DBG_INIT, - "brightness support disabled by " - "module parameter\n"); - return 1; - } else if (brightness_enable > 1) { - if (brightness_check_std_acpi_support()) { + /* + * We always attempt to detect acpi support, so as to switch + * Lenovo Vista BIOS to ACPI brightness mode even if we are not + * going to publish a backlight interface + */ + b = tpacpi_check_std_acpi_brightness_support(); + if (b > 0) { + if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { + printk(TPACPI_NOTICE + "Lenovo BIOS switched to ACPI backlight " + "control mode\n"); + } + if (brightness_enable > 1) { printk(TPACPI_NOTICE "standard ACPI backlight interface " "available, not loading native one...\n"); @@ -4389,6 +4743,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm) } } + if (!brightness_enable) { + dbg_printk(TPACPI_DBG_INIT, + "brightness support disabled by " + "module parameter\n"); + return 1; + } + + if (b > 16) { + printk(TPACPI_ERR + "Unsupported brightness interface, " + "please contact %s\n", TPACPI_MAIL); + return 1; + } + if (b == 16) + tp_features.bright_16levels = 1; + if (!brightness_mode) { if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) brightness_mode = 2; @@ -4402,12 +4772,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (brightness_mode > 3) return -EINVAL; - tp_features.bright_16levels = - thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO && - brightness_check_levels(); - - b = brightness_get(NULL); - if (b < 0) + if (brightness_get_raw(&b) < 0) return 1; if (tp_features.bright_16levels) @@ -4425,7 +4790,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) ibm_backlight_device->props.max_brightness = (tp_features.bright_16levels)? 15 : 7; - ibm_backlight_device->props.brightness = b; + ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; backlight_update_status(ibm_backlight_device); return 0; @@ -5046,11 +5411,11 @@ static void fan_watchdog_reset(void) if (fan_watchdog_maxinterval > 0 && tpacpi_lifecycle != TPACPI_LIFE_EXITING) { fan_watchdog_active = 1; - if (!schedule_delayed_work(&fan_watchdog_task, + if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task, msecs_to_jiffies(fan_watchdog_maxinterval * 1000))) { printk(TPACPI_ERR - "failed to schedule the fan watchdog, " + "failed to queue the fan watchdog, " "watchdog will not trigger\n"); } } else @@ -5420,7 +5785,7 @@ static void fan_exit(void) &driver_attr_fan_watchdog); cancel_delayed_work(&fan_watchdog_task); - flush_scheduled_work(); + flush_workqueue(tpacpi_wq); } static int fan_read(char *p) @@ -5826,10 +6191,13 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), GFP_KERNEL); - if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) { + if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) { kfree(tp->model_str); tp->model_str = NULL; } + + tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME), + GFP_KERNEL); } static int __init probe_for_thinkpad(void) @@ -6071,6 +6439,9 @@ static void thinkpad_acpi_module_exit(void) if (proc_dir) remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); + if (tpacpi_wq) + destroy_workqueue(tpacpi_wq); + kfree(thinkpad_id.bios_version_str); kfree(thinkpad_id.ec_version_str); kfree(thinkpad_id.model_str); @@ -6101,6 +6472,12 @@ static int __init thinkpad_acpi_module_init(void) TPACPI_ACPIHANDLE_INIT(ecrd); TPACPI_ACPIHANDLE_INIT(ecwr); + tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME); + if (!tpacpi_wq) { + thinkpad_acpi_module_exit(); + return -ENOMEM; + } + proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir); if (!proc_dir) { printk(TPACPI_ERR @@ -6223,6 +6600,8 @@ static int __init thinkpad_acpi_module_init(void) /* Please remove this in year 2009 */ MODULE_ALIAS("ibm_acpi"); +MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); + /* * DMI matching for module autoloading * diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 365024b83d3d..35508584ac2a 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -340,7 +340,7 @@ checkstatus: /* SPI R3, R4, or R7 == R1 + 4 bytes */ case MMC_RSP_SPI_R3: - cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + cmd->resp[1] = get_unaligned_be32(cp); break; /* SPI R1 == just one status byte */ diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 95244a7e7353..626ac083f4e0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -213,9 +213,10 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema void __iomem *base = host->base; char *ptr = buffer; u32 status; + int host_remain = host->size; do { - int count = host->size - (readl(base + MMCIFIFOCNT) << 2); + int count = host_remain - (readl(base + MMCIFIFOCNT) << 2); if (count > remain) count = remain; @@ -227,6 +228,7 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema ptr += count; remain -= count; + host_remain -= count; if (remain == 0) break; diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index e812df607a5c..fcd1aeccdf93 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *); static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **); static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **mtdbuf); -static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, - size_t len); + size_t *retlen, void **virt, resource_size_t *phys); +static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len); static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode); static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); @@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a return ret; } -static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) +static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); - *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs; + *virt = map->virt + cfi->chips[chipnum].start + ofs; *retlen = 0; + if (phys) + *phys = map->phys + cfi->chips[chipnum].start + ofs; while (len) { unsigned long thislen; @@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si return 0; } -static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index bf485ff49457..0399be178620 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) } static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **mtdbuf) + size_t *retlen, void **virt, resource_size_t *phys) { if (from + len > mtd->size) return -EINVAL; - *mtdbuf = mtd->priv + from; + /* can we return a physical address with this driver? */ + if (phys) + return -EINVAL; + + *virt = mtd->priv + from; *retlen = len; return 0; } -static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, - size_t len) +static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { } diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 5f960182da95..c7987b1c5e01 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) } static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **mtdbuf) + size_t *retlen, void **virt, resource_size_t *phys) { - u_char *start = mtd->priv; - if (from + len > mtd->size) return -EINVAL; - *mtdbuf = start + from; + /* can we return a physical address with this driver? */ + if (phys) + return -EINVAL; + + *virt = mtd->priv + from; *retlen = len; return 0; } -static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, - size_t len) +static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { } diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 7060a0895ce2..bc9981749064 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) eoff_lo = end & (priv->asize - 1); soff_lo = instr->addr & (priv->asize - 1); - pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr); + pmc551_point(mtd, instr->addr, instr->len, &retlen, + (void **)&ptr, NULL); if (soff_hi == eoff_hi || mtd->size == priv->asize) { /* The whole thing fits within one access, so just one shot @@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) } soff_hi += priv->asize; pmc551_point(mtd, (priv->base_map0 | soff_hi), - priv->asize, &retlen, &ptr); + priv->asize, &retlen, + (void **)&ptr, NULL); } memset(ptr, 0xff, eoff_lo); } @@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) } static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char ** mtdbuf) + size_t *retlen, void **virt, resource_size_t *phys) { struct mypriv *priv = mtd->priv; u32 soff_hi; @@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, return -EINVAL; } + /* can we return a physical address with this driver? */ + if (phys) + return -EINVAL; + soff_hi = from & ~(priv->asize - 1); soff_lo = from & (priv->asize - 1); @@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, priv->curr_map0 = soff_hi; } - *mtdbuf = priv->start + soff_lo; + *virt = priv->start + soff_lo; *retlen = len; return 0; } -static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, - size_t len) +static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { #ifdef CONFIG_MTD_PMC551_DEBUG printk(KERN_DEBUG "pmc551_unpoint()\n"); @@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, soff_lo = from & (priv->asize - 1); eoff_lo = end & (priv->asize - 1); - pmc551_point(mtd, from, len, retlen, &ptr); + pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL); if (soff_hi == eoff_hi) { /* The whole thing fits within one access, so just one shot @@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, goto out; } soff_hi += priv->asize; - pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr); + pmc551_point(mtd, soff_hi, priv->asize, retlen, + (void **)&ptr, NULL); } memcpy(copyto, ptr, eoff_lo); copyto += eoff_lo; @@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, soff_lo = to & (priv->asize - 1); eoff_lo = end & (priv->asize - 1); - pmc551_point(mtd, to, len, retlen, &ptr); + pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL); if (soff_hi == eoff_hi) { /* The whole thing fits within one access, so just one shot @@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, goto out; } soff_hi += priv->asize; - pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr); + pmc551_point(mtd, soff_hi, priv->asize, retlen, + (void **)&ptr, NULL); } memcpy(ptr, copyfrom, eoff_lo); copyfrom += eoff_lo; diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index d293add1857c..cb86db746f28 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -76,8 +76,9 @@ static char *map; static slram_mtd_list_t *slram_mtdlist = NULL; static int slram_erase(struct mtd_info *, struct erase_info *); -static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **); -static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t); +static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **, + resource_size_t *); +static void slram_unpoint(struct mtd_info *, loff_t, size_t); static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) } static int slram_point(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **mtdbuf) + size_t *retlen, void **virt, resource_size_t *phys) { slram_priv_t *priv = mtd->priv; + /* can we return a physical address with this driver? */ + if (phys) + return -EINVAL; + if (from + len > mtd->size) return -EINVAL; - *mtdbuf = priv->start + from; + *virt = priv->start + from; *retlen = len; return(0); } -static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { } diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index f0b10ca05029..3eb2643b2328 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -209,7 +209,7 @@ static int platram_probe(struct platform_device *pdev) /* probe for the right mtd map driver * supplied by the platform_data struct */ - if (pdata->map_probes != 0) { + if (pdata->map_probes) { const char **map_probes = pdata->map_probes; for ( ; !info->mtd && *map_probes; map_probes++) diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 14ffb1a9302a..c42f4b83f686 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = { /****************************************************************************/ int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **mtdbuf) + size_t *retlen, void **virt, resource_size_t *phys) { struct map_info *map = mtd->priv; - *mtdbuf = (u_char *) (map->virt + ((int) from)); + *virt = map->virt + from; + if (phys) + *phys = map->phys + from; *retlen = len; return(0); } diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index c66902df3171..07c701169344 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, } static int part_point (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **buf) + size_t *retlen, void **virt, resource_size_t *phys) { struct mtd_part *part = PART(mtd); if (from >= mtd->size) @@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, else if (from + len > mtd->size) len = mtd->size - from; return part->master->point (part->master, from + part->offset, - len, retlen, buf); + len, retlen, virt, phys); } -static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { struct mtd_part *part = PART(mtd); - part->master->unpoint (part->master, addr, from + part->offset, len); + part->master->unpoint(part->master, from + part->offset, len); } static int part_read_oob(struct mtd_info *mtd, loff_t from, diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c index 414ceaecdb3a..0adb287027a2 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/at91_nand.c @@ -94,6 +94,24 @@ struct at91_nand_host { }; /* + * Enable NAND. + */ +static void at91_nand_enable(struct at91_nand_host *host) +{ + if (host->board->enable_pin) + at91_set_gpio_value(host->board->enable_pin, 0); +} + +/* + * Disable NAND. + */ +static void at91_nand_disable(struct at91_nand_host *host) +{ + if (host->board->enable_pin) + at91_set_gpio_value(host->board->enable_pin, 1); +} + +/* * Hardware specific access to control-lines */ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) @@ -101,11 +119,11 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) struct nand_chip *nand_chip = mtd->priv; struct at91_nand_host *host = nand_chip->priv; - if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) { + if (ctrl & NAND_CTRL_CHANGE) { if (ctrl & NAND_NCE) - at91_set_gpio_value(host->board->enable_pin, 0); + at91_nand_enable(host); else - at91_set_gpio_value(host->board->enable_pin, 1); + at91_nand_disable(host); } if (cmd == NAND_CMD_NONE) return; @@ -128,24 +146,6 @@ static int at91_nand_device_ready(struct mtd_info *mtd) } /* - * Enable NAND. - */ -static void at91_nand_enable(struct at91_nand_host *host) -{ - if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 0); -} - -/* - * Disable NAND. - */ -static void at91_nand_disable(struct at91_nand_host *host) -{ - if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 1); -} - -/* * write oob for small pages */ static int at91_nand_write_oob_512(struct mtd_info *mtd, diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 9c6573419f5a..fdfb2b2cb734 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 1910cb1dc787..04df2a9002b6 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 54dac0696d91..e6c545fe5f58 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 6ab84b661d70..105a8c7ca7e9 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 8082c1d142df..af46341827f2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -469,7 +469,7 @@ config SNI_82596 config KORINA tristate "Korina (IDT RC32434) Ethernet support" - depends on NET_ETHERNET && MIKROTIK_RB500 + depends on NET_ETHERNET && MIKROTIK_RB532 help If you have a Mikrotik RouterBoard 500 or IDT RC32434 based system say Y. Otherwise say N. @@ -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 2f1f3f2739fd..dcbfe8421154 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 f9cc2b621fe2..8eda6eeb43b7 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 a4c868278e11..7c812ac2b6a5 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/am79c961a.c b/drivers/net/arm/am79c961a.c index ba6bd03a015f..a637910b02dd 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -693,11 +693,15 @@ static int __init am79c961_probe(struct platform_device *pdev) * done by the ether bootp loader. */ dev->base_addr = res->start; - dev->irq = platform_get_irq(pdev, 0); + ret = platform_get_irq(pdev, 0); - ret = -ENODEV; - if (dev->irq < 0) + if (ret < 0) { + ret = -ENODEV; goto nodev; + } + dev->irq = ret; + + ret = -ENODEV; if (!request_region(dev->base_addr, 0x18, dev->name)) goto nodev; diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c new file mode 100644 index 000000000000..c617b64c288e --- /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 4fec8581bfd7..89c0018132ec 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 f774d5a36942..beff51064ff4 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/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6e91b4b7aabb..6425603bc379 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3282,17 +3282,14 @@ static int bond_create_proc_entry(struct bonding *bond) struct net_device *bond_dev = bond->dev; if (bond_proc_dir) { - bond->proc_entry = create_proc_entry(bond_dev->name, - S_IRUGO, - bond_proc_dir); + bond->proc_entry = proc_create_data(bond_dev->name, + S_IRUGO, bond_proc_dir, + &bond_info_fops, bond); if (bond->proc_entry == NULL) { printk(KERN_WARNING DRV_NAME ": Warning: Cannot create /proc/net/%s/%s\n", DRV_NAME, bond_dev->name); } else { - bond->proc_entry->data = bond; - bond->proc_entry->proc_fops = &bond_info_fops; - bond->proc_entry->owner = THIS_MODULE; memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } } diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 229303ff6a39..a0177fc55e28 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -38,7 +38,7 @@ #define DRV_VERSION "1.0-ko" /* Firmware version */ -#define FW_VERSION_MAJOR 5 +#define FW_VERSION_MAJOR 6 #define FW_VERSION_MINOR 0 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 2d139ec79777..f3cba5e24ec5 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1802,7 +1802,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) * it is protected by the before last buffer's el bit being set */ if (rx->prev->skb) { struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; - put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link); + put_unaligned_le32(rx->dma_addr, &prev_rfd->link); } return 0; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 83bda6ccde98..56f50491a453 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.c b/drivers/net/fec.c index d7a3ea88eddb..32a4f17d35fc 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -67,6 +67,10 @@ #define FEC_MAX_PORTS 1 #endif +#if defined(CONFIG_FADS) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_M5272) +#define HAVE_mii_link_interrupt +#endif + /* * Define the fixed address of the FEC hardware. */ @@ -205,7 +209,10 @@ struct fec_enet_private { cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ cbd_t *dirty_tx; /* The ring entries to be free()ed. */ uint tx_full; - spinlock_t lock; + /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ + spinlock_t hw_lock; + /* hold while accessing the mii_list_t() elements */ + spinlock_t mii_lock; uint phy_id; uint phy_id_done; @@ -309,6 +316,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) volatile fec_t *fecp; volatile cbd_t *bdp; unsigned short status; + unsigned long flags; fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; @@ -318,6 +326,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) return 1; } + spin_lock_irqsave(&fep->hw_lock, flags); /* Fill in a Tx ring entry */ bdp = fep->cur_tx; @@ -328,6 +337,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) * This should not happen, since dev->tbusy should be set. */ printk("%s: tx queue full!.\n", dev->name); + spin_unlock_irqrestore(&fep->hw_lock, flags); return 1; } #endif @@ -366,8 +376,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) flush_dcache_range((unsigned long)skb->data, (unsigned long)skb->data + skb->len); - spin_lock_irq(&fep->lock); - /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ @@ -396,7 +404,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) fep->cur_tx = (cbd_t *)bdp; - spin_unlock_irq(&fep->lock); + spin_unlock_irqrestore(&fep->hw_lock, flags); return 0; } @@ -454,19 +462,20 @@ fec_enet_interrupt(int irq, void * dev_id) struct net_device *dev = dev_id; volatile fec_t *fecp; uint int_events; - int handled = 0; + irqreturn_t ret = IRQ_NONE; fecp = (volatile fec_t*)dev->base_addr; /* Get the interrupt events that caused us to be here. */ - while ((int_events = fecp->fec_ievent) != 0) { + do { + int_events = fecp->fec_ievent; fecp->fec_ievent = int_events; /* Handle receive event in its own function. */ if (int_events & FEC_ENET_RXF) { - handled = 1; + ret = IRQ_HANDLED; fec_enet_rx(dev); } @@ -475,17 +484,18 @@ fec_enet_interrupt(int irq, void * dev_id) them as part of the transmit process. */ if (int_events & FEC_ENET_TXF) { - handled = 1; + ret = IRQ_HANDLED; fec_enet_tx(dev); } if (int_events & FEC_ENET_MII) { - handled = 1; + ret = IRQ_HANDLED; fec_enet_mii(dev); } - } - return IRQ_RETVAL(handled); + } while (int_events); + + return ret; } @@ -498,7 +508,7 @@ fec_enet_tx(struct net_device *dev) struct sk_buff *skb; fep = netdev_priv(dev); - spin_lock(&fep->lock); + spin_lock_irq(&fep->hw_lock); bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { @@ -557,7 +567,7 @@ fec_enet_tx(struct net_device *dev) } } fep->dirty_tx = (cbd_t *)bdp; - spin_unlock(&fep->lock); + spin_unlock_irq(&fep->hw_lock); } @@ -584,6 +594,8 @@ fec_enet_rx(struct net_device *dev) fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; + spin_lock_irq(&fep->hw_lock); + /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ @@ -689,6 +701,8 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { */ fecp->fec_r_des_active = 0; #endif + + spin_unlock_irq(&fep->hw_lock); } @@ -702,11 +716,11 @@ fec_enet_mii(struct net_device *dev) uint mii_reg; fep = netdev_priv(dev); + spin_lock_irq(&fep->mii_lock); + ep = fep->hwp; mii_reg = ep->fec_mii_data; - spin_lock(&fep->lock); - if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); goto unlock; @@ -723,7 +737,7 @@ fec_enet_mii(struct net_device *dev) ep->fec_mii_data = mip->mii_regval; unlock: - spin_unlock(&fep->lock); + spin_unlock_irq(&fep->mii_lock); } static int @@ -737,12 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi /* Add PHY address to register command. */ fep = netdev_priv(dev); - regval |= fep->phy_addr << 23; + spin_lock_irqsave(&fep->mii_lock, flags); + regval |= fep->phy_addr << 23; retval = 0; - spin_lock_irqsave(&fep->lock,flags); - if ((mip = mii_free) != NULL) { mii_free = mip->mii_next; mip->mii_regval = regval; @@ -759,9 +772,8 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi retval = 1; } - spin_unlock_irqrestore(&fep->lock,flags); - - return(retval); + spin_unlock_irqrestore(&fep->mii_lock, flags); + return retval; } static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) @@ -1222,7 +1234,7 @@ static phy_info_t const * const phy_info[] = { }; /* ------------------------------------------------------------------------- */ -#if !defined(CONFIG_M532x) +#ifdef HAVE_mii_link_interrupt #ifdef CONFIG_RPXCLASSIC static void mii_link_interrupt(void *dev_id); @@ -1362,18 +1374,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev) unsigned short irq; } *idp, id[] = { { "fec(TXF)", 23 }, - { "fec(TXB)", 24 }, - { "fec(TXFIFO)", 25 }, - { "fec(TXCR)", 26 }, { "fec(RXF)", 27 }, - { "fec(RXB)", 28 }, { "fec(MII)", 29 }, - { "fec(LC)", 30 }, - { "fec(HBERR)", 31 }, - { "fec(GRA)", 32 }, - { "fec(EBERR)", 33 }, - { "fec(BABT)", 34 }, - { "fec(BABR)", 35 }, { NULL }, }; @@ -1533,18 +1535,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev) unsigned short irq; } *idp, id[] = { { "fec(TXF)", 23 }, - { "fec(TXB)", 24 }, - { "fec(TXFIFO)", 25 }, - { "fec(TXCR)", 26 }, { "fec(RXF)", 27 }, - { "fec(RXB)", 28 }, { "fec(MII)", 29 }, - { "fec(LC)", 30 }, - { "fec(HBERR)", 31 }, - { "fec(GRA)", 32 }, - { "fec(EBERR)", 33 }, - { "fec(BABT)", 34 }, - { "fec(BABR)", 35 }, { NULL }, }; @@ -1660,18 +1652,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev) unsigned short irq; } *idp, id[] = { { "fec(TXF)", 36 }, - { "fec(TXB)", 37 }, - { "fec(TXFIFO)", 38 }, - { "fec(TXCR)", 39 }, { "fec(RXF)", 40 }, - { "fec(RXB)", 41 }, { "fec(MII)", 42 }, - { "fec(LC)", 43 }, - { "fec(HBERR)", 44 }, - { "fec(GRA)", 45 }, - { "fec(EBERR)", 46 }, - { "fec(BABT)", 47 }, - { "fec(BABR)", 48 }, { NULL }, }; @@ -2126,6 +2108,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) /* This interrupt occurs when the PHY detects a link change. */ +#ifdef HAVE_mii_link_interrupt #ifdef CONFIG_RPXCLASSIC static void mii_link_interrupt(void *dev_id) @@ -2148,6 +2131,7 @@ mii_link_interrupt(int irq, void * dev_id) return IRQ_HANDLED; } +#endif static int fec_enet_open(struct net_device *dev) @@ -2243,13 +2227,13 @@ static void set_multicast_list(struct net_device *dev) /* Catch all multicast addresses, so set the * filter to all 1's. */ - ep->fec_hash_table_high = 0xffffffff; - ep->fec_hash_table_low = 0xffffffff; + ep->fec_grp_hash_table_high = 0xffffffff; + ep->fec_grp_hash_table_low = 0xffffffff; } else { /* Clear filter and add the addresses in hash register. */ - ep->fec_hash_table_high = 0; - ep->fec_hash_table_low = 0; + ep->fec_grp_hash_table_high = 0; + ep->fec_grp_hash_table_low = 0; dmi = dev->mc_list; @@ -2280,9 +2264,9 @@ static void set_multicast_list(struct net_device *dev) hash = (crc >> (32 - HASH_BITS)) & 0x3f; if (hash > 31) - ep->fec_hash_table_high |= 1 << (hash - 32); + ep->fec_grp_hash_table_high |= 1 << (hash - 32); else - ep->fec_hash_table_low |= 1 << hash; + ep->fec_grp_hash_table_low |= 1 << hash; } } } @@ -2332,6 +2316,9 @@ int __init fec_enet_init(struct net_device *dev) return -ENOMEM; } + spin_lock_init(&fep->hw_lock); + spin_lock_init(&fep->mii_lock); + /* Create an Ethernet device instance. */ fecp = (volatile fec_t *) fec_hw[index]; @@ -2430,11 +2417,15 @@ int __init fec_enet_init(struct net_device *dev) */ fec_request_intrs(dev); - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; + fecp->fec_grp_hash_table_high = 0; + fecp->fec_grp_hash_table_low = 0; fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; fecp->fec_ecntrl = 2; fecp->fec_r_des_active = 0; +#ifndef CONFIG_M5272 + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; +#endif dev->base_addr = (unsigned long)fecp; @@ -2455,8 +2446,7 @@ int __init fec_enet_init(struct net_device *dev) /* Clear and enable interrupts */ fecp->fec_ievent = 0xffc00000; - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); /* Queue up command to detect the PHY and initialize the * remainder of the interface. @@ -2500,8 +2490,8 @@ fec_restart(struct net_device *dev, int duplex) /* Reset all multicast. */ - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; + fecp->fec_grp_hash_table_high = 0; + fecp->fec_grp_hash_table_low = 0; /* Set maximum receive buffer size. */ @@ -2583,8 +2573,7 @@ fec_restart(struct net_device *dev, int duplex) /* Enable interrupts we wish to service. */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); } static void @@ -2624,7 +2613,7 @@ fec_stop(struct net_device *dev) static int __init fec_enet_module_init(void) { struct net_device *dev; - int i, j, err; + int i, err; DECLARE_MAC_BUF(mac); printk("FEC ENET Version 0.2\n"); diff --git a/drivers/net/fec.h b/drivers/net/fec.h index 1d421606984f..292719daceff 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -88,8 +88,8 @@ typedef struct fec { unsigned long fec_reserved7[158]; unsigned long fec_addr_low; /* Low 32bits MAC address */ unsigned long fec_addr_high; /* High 16bits MAC address */ - unsigned long fec_hash_table_high; /* High 32bits hash table */ - unsigned long fec_hash_table_low; /* Low 32bits hash table */ + unsigned long fec_grp_hash_table_high;/* High 32bits hash table */ + unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */ unsigned long fec_r_des_start; /* Receive descriptor ring */ unsigned long fec_x_des_start; /* Transmit descriptor ring */ unsigned long fec_r_buff_size; /* Maximum receive buff size */ diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index e5e6352556fa..d21b7ab64bd1 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 99a4b990939f..587afe7be689 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 0d0883609469..fd487be3993e 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 b8898927236a..ebcfb27a904e 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 b373091c7031..2af28b16a0e2 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/hamachi.c b/drivers/net/hamachi.c index b53f6b6491b3..e5c2380f50ca 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1508,7 +1508,7 @@ static int hamachi_rx(struct net_device *dev) hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; - frame_status = le32_to_cpu(get_unaligned((__le32*)&(buf_addr[data_size - 12]))); + frame_status = get_unaligned_le32(&(buf_addr[data_size - 12])); if (hamachi_debug > 4) printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", frame_status); diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 1da55dd2a5a0..9d5721287d6f 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 30c9b3b0d131..65166035aca0 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/ibmveth.c b/drivers/net/ibmveth.c index ce4fc2ec2fe4..00527805e4f1 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1302,13 +1302,10 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) if (ibmveth_proc_dir) { char u_addr[10]; sprintf(u_addr, "%x", adapter->vdev->unit_address); - entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); - if (!entry) { + entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir, + &ibmveth_proc_fops, adapter); + if (!entry) ibmveth_error_printk("Cannot create adapter proc entry"); - } else { - entry->data = (void *) adapter; - entry->proc_fops = &ibmveth_proc_fops; - } } return; } diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index fc753d7f674e..e6f40b7f9041 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/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 93916cf33f29..ad92d3ff1c40 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -464,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) } fcs = ~(crc32_le(~0, buf, new_len)); - if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) { + if(fcs != get_unaligned_le32(buf + new_len)) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); mcs->stats.rx_errors++; mcs->stats.rx_crc_errors++; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index e59c485bc497..051963782749 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -329,7 +329,7 @@ static void fir_eof(struct stir_cb *stir) } fcs = ~(crc32_le(~0, rx_buff->data, len)); - if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) { + if (fcs != get_unaligned_le32(rx_buff->data + len)) { pr_debug("crc error calc 0x%x len %d\n", fcs, len); stir->stats.rx_errors++; stir->stats.rx_crc_errors++; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index acd082a96a4f..d15e00b8591e 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1674,13 +1674,12 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (vlsi_proc_root != NULL) { struct proc_dir_entry *ent; - ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root); + ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO, + vlsi_proc_root, VLSI_PROC_FOPS, ndev); if (!ent) { IRDA_WARNING("%s: failed to create proc entry\n", __FUNCTION__); } else { - ent->data = ndev; - ent->proc_fops = VLSI_PROC_FOPS; ent->size = 0; } idev->proc_entry = ent; diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 6fda0af9d0a6..95e87a2f8896 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -188,7 +188,8 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, EXPORT_SYMBOL_GPL(mlx4_cq_resize); int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, - struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq) + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + int collapsed) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cq_table *cq_table = &priv->cq_table; @@ -224,6 +225,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, cq_context = mailbox->buf; memset(cq_context, 0, sizeof *cq_context); + cq_context->flags = cpu_to_be32(!!collapsed << 18); cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); cq_context->comp_eqn = priv->eq_table.eq[MLX4_EQ_COMP].eqn; cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 79b317b88c86..cb46446b2691 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -607,15 +607,9 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_enable); void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u32 *lkey, u32 *rkey) { - u32 key; - if (!fmr->maps) return; - key = key_to_hw_index(fmr->mr.key); - key &= dev->caps.num_mpts - 1; - *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); - fmr->maps = 0; *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index cead81e80f0c..ef63c8d2bd7e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2437,7 +2437,7 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) int status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto drop; while (segs) { diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 3ac8529bb92c..6bf9e76b0a00 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 ddf8d51832a6..ac3c01d28fdf 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 b1d8ed40ad98..73baa7a3bb0e 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 f023d5b67e6e..f1a52def1241 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 0d80fa546719..b8f0369a71e7 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/pppoe.c b/drivers/net/pppoe.c index 4fad4ddb3504..58a26a47af29 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1052,11 +1052,9 @@ static int __init pppoe_proc_init(void) { struct proc_dir_entry *p; - p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net); + p = proc_net_fops_create(&init_net, "pppoe", S_IRUGO, &pppoe_seq_fops); if (!p) return -ENOMEM; - - p->proc_fops = &pppoe_seq_fops; return 0; } #else /* CONFIG_PROC_FS */ diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 3d10ca050b79..244d7830c92a 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -2469,12 +2469,12 @@ static int __init pppol2tp_init(void) goto out_unregister_pppol2tp_proto; #ifdef CONFIG_PROC_FS - pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net); + pppol2tp_proc = proc_net_fops_create(&init_net, "pppol2tp", 0, + &pppol2tp_proc_fops); if (!pppol2tp_proc) { err = -ENOMEM; goto out_unregister_pppox_proto; } - pppol2tp_proc->proc_fops = &pppol2tp_proc_fops; #endif /* CONFIG_PROC_FS */ printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", PPPOL2TP_DRV_VERSION); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 3acfeeabdee1..657242504621 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/rionet.c b/drivers/net/rionet.c index e7fd08adbbac..2b8fd68bc516 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -77,7 +77,7 @@ static int rionet_capable = 1; * could be made into a hash table to save memory depending * on system trade-offs. */ -static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; +static struct rio_dev **rionet_active; #define is_rionet_capable(pef, src_ops, dst_ops) \ ((pef & RIO_PEF_INB_MBOX) && \ @@ -195,7 +195,8 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) } if (eth->h_dest[0] & 0x01) { - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); + i++) if (rionet_active[i]) rionet_queue_tx_msg(skb, ndev, rionet_active[i]); @@ -385,6 +386,8 @@ static void rionet_remove(struct rio_dev *rdev) struct net_device *ndev = NULL; struct rionet_peer *peer, *tmp; + free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ? + __ilog2(sizeof(void *)) + 4 : 0); unregister_netdev(ndev); kfree(ndev); @@ -443,6 +446,15 @@ static int rionet_setup_netdev(struct rio_mport *mport) goto out; } + rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, + mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0); + if (!rionet_active) { + rc = -ENOMEM; + goto out; + } + memset((void *)rionet_active, 0, sizeof(void *) * + RIO_MAX_ROUTE_ENTRIES(mport->sys_size)); + /* Set up private area */ rnet = (struct rionet_private *)ndev->priv; rnet->mport = mport; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 157fd932e951..523478ebfd69 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 ce53a02105f2..0709ebae9139 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 000000000000..dbad95c295bd --- /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 000000000000..0f023447eafd --- /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 000000000000..2806201644cc --- /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 000000000000..eecaa6d58584 --- /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 000000000000..f56341d428e1 --- /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 000000000000..59edcf793c19 --- /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 000000000000..3b2f69f4a9ab --- /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 000000000000..43663a4619da --- /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 000000000000..ad541badbd98 --- /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 000000000000..3628e43df14d --- /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 000000000000..46db549ce580 --- /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, ®, 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, ®, GPIO_CTL_REG_KER); +} + +static int falcon_getsda(struct efx_i2c_interface *i2c) +{ + efx_oword_t reg; + + falcon_read(i2c->efx, ®, 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, ®, 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, ®, + 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, ®, TX_CHKSM_CFG_REG_KER_A1); + if (efx->net_dev->features & NETIF_F_IP_CSUM) + clear_bit_le(tx_queue->queue, (void *)®); + else + set_bit_le(tx_queue->queue, (void *)®); + falcon_write(efx, ®, 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, ®, 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, ®, + 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, ®, 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, ®, 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, ®, INT_ACK_REG_KER_A1); + falcon_readl(efx, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, EE_SPI_HCMD_REG_KER); + + /* Wait for read to complete */ + rc = falcon_spi_wait(efx); + if (rc) + return rc; + + /* Read data */ + falcon_read(efx, ®, EE_SPI_HDATA_REG_KER); + memcpy(data, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, MD_PHY_ADR_REG_KER); + + EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2); + falcon_write(efx, ®, MD_ID_REG_KER); + + /* Write data */ + EFX_POPULATE_OWORD_1(reg, MD_TXD, value); + falcon_write(efx, ®, MD_TXD_REG_KER); + + EFX_POPULATE_OWORD_2(reg, + MD_WRC, 1, + MD_GC, 0); + falcon_write(efx, ®, 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, ®, 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, ®, MD_PHY_ADR_REG_KER); + + EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr); + falcon_write(efx, ®, MD_ID_REG_KER); + + /* Request data to be read */ + EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0); + falcon_write(efx, ®, MD_CS_REG_KER); + + /* Wait for data to become available */ + value = falcon_gmii_wait(efx); + if (value == 0) { + falcon_read(efx, ®, 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, ®, 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 000000000000..6117403b0c03 --- /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 000000000000..0485a63eaff6 --- /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 000000000000..ea08184ddfa9 --- /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 000000000000..aa7521b24a5d --- /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, ®, XM_GLB_CFG_REG_MAC); + + for (count = 0; count < 10000; count++) { /* wait upto 100ms */ + falcon_xmac_readl(efx, ®, 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, ®, 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, ®, 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, ®, XX_PWR_RST_REG_MAC); + udelay(10); + + EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0); + falcon_xmac_writel(efx, ®, 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, ®, 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, ®, XX_PWR_RST_REG_MAC); + udelay(10); + + EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0); + falcon_xmac_writel(efx, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, XM_MGT_INT_REG_MAC_B0); + falcon_xmac_readl(efx, ®, 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, ®, XM_MGT_INT_REG_MAC_B0); + + EFX_POPULATE_DWORD_2(reg, + XM_MSK_RMTFLT, !enable, + XM_MSK_LCLFLT, !enable); + falcon_xmac_writel(efx, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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 000000000000..d25bbd1297f4 --- /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 000000000000..b6c62d0ed9c2 --- /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 000000000000..291e561071f5 --- /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 000000000000..edd07d4dee18 --- /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 000000000000..dc06bb0aa575 --- /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 000000000000..2214b6d820a7 --- /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 000000000000..c505482c2520 --- /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 000000000000..9d02c84e6b2d --- /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 000000000000..551299b462ae --- /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 000000000000..f35e377bfc5f --- /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 000000000000..11fa9fb8f48b --- /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, ®, 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 000000000000..34412f3d41c9 --- /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 000000000000..a2e9f79e47b1 --- /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 000000000000..fbb866b2185e --- /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 000000000000..1526a73b4b51 --- /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 000000000000..dca62f190198 --- /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 000000000000..b0d1f225b70a --- /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 000000000000..66dd5bf1eaa9 --- /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 20745fd4e973..abc63b0663be 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 5a55ede352f4..84af68fdb6c2 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/tehuti.c b/drivers/net/tehuti.c index e83b166aa6b9..432e837a1760 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -649,7 +649,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); } - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; switch (data[0]) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e3f74c9f78bd..b66c75e3b8a1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4361,7 +4361,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto tg3_tso_bug_end; do { diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 6c6fc325c8f9..bc30c6e8fea2 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -482,7 +482,6 @@ static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #define c_char const char -#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a))) /* ** MII Information @@ -4405,7 +4404,7 @@ srom_infoleaf_info(struct net_device *dev) } } - lp->infoleaf_offset = TWIDDLE(p+1); + lp->infoleaf_offset = get_unaligned_le16(p + 1); return 0; } @@ -4476,7 +4475,7 @@ srom_exec(struct net_device *dev, u_char *p) while (count--) { gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? - *p++ : TWIDDLE(w++)), dev); + *p++ : get_unaligned_le16(w++)), dev); mdelay(2); /* 2ms per action */ } @@ -4711,10 +4710,10 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p) lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : NULL); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : NULL); p += (*p + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); + lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ttm = get_unaligned_le16(p); return 0; } else if ((lp->media == INIT) && (lp->timeout < 0)) { lp->ibn = 1; @@ -4751,16 +4750,16 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p) lp->infoblock_media = (*p) & MEDIA_CODE; if ((*p++) & EXT_FIELD) { - lp->cache.csr13 = TWIDDLE(p); p += 2; - lp->cache.csr14 = TWIDDLE(p); p += 2; - lp->cache.csr15 = TWIDDLE(p); p += 2; + lp->cache.csr13 = get_unaligned_le16(p); p += 2; + lp->cache.csr14 = get_unaligned_le16(p); p += 2; + lp->cache.csr15 = get_unaligned_le16(p); p += 2; } else { lp->cache.csr13 = CSR13; lp->cache.csr14 = CSR14; lp->cache.csr15 = CSR15; } - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); + lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2; + lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); lp->infoblock_csr6 = OMR_SIA; lp->useMII = false; @@ -4792,10 +4791,10 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p) if (MOTO_SROM_BUG) lp->active = 0; lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1); lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); p += 2; + lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ttm = get_unaligned_le16(p); p += 2; lp->phy[lp->active].mci = *p; return 0; } else if ((lp->media == INIT) && (lp->timeout < 0)) { @@ -4835,8 +4834,8 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p) lp->cache.csr13 = CSR13; /* Hard coded defaults */ lp->cache.csr14 = CSR14; lp->cache.csr15 = CSR15; - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2; + lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2; + lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); p += 2; csr6 = *p++; flags = *p++; diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h index 9fb8d7f07994..f5f33b3eb067 100644 --- a/drivers/net/tulip/de4x5.h +++ b/drivers/net/tulip/de4x5.h @@ -1017,4 +1017,4 @@ struct de4x5_ioctl { #define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */ #define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */ -#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008)) +#define MOTO_SROM_BUG (lp->active == 8 && (get_unaligned_le32(dev->dev_addr) & 0x00ffffff) == 0x3e0008) diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 908422f2f320..92c68a22f16b 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/unaligned.h> @@ -304,11 +305,7 @@ enum t21143_csr6_bits { #define RUN_AT(x) (jiffies + (x)) -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif +#define get_u16(ptr) get_unaligned_le16((ptr)) struct medialeaf { u8 type; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index fa1c1c329a2d..f9d13fa05d64 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -327,8 +327,8 @@ static void tulip_up(struct net_device *dev) tp->dirty_rx = tp->dirty_tx = 0; if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr)); - u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4))); + u32 addr_low = get_unaligned_le32(dev->dev_addr); + u32 addr_high = get_unaligned_le16(dev->dev_addr + 4); if (tp->chip_id == AX88140) { iowrite32(0, ioaddr + CSR13); iowrite32(addr_low, ioaddr + CSR14); @@ -1437,13 +1437,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, do value = ioread32(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); - put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i); + put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ - put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr); - put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4)); + put_unaligned_le32(ioread32(ioaddr + 0xA4), dev->dev_addr); + put_unaligned_le16(ioread32(ioaddr + 0xA8), dev->dev_addr + 4); for (i = 0; i < 6; i ++) sum += dev->dev_addr[i]; } else { diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 555b70c8b863..f926b5ab3d09 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -41,6 +41,9 @@ struct virtnet_info struct net_device *dev; struct napi_struct napi; + /* The skb we couldn't send because buffers were full. */ + struct sk_buff *last_xmit_skb; + /* Number of input buffers, and max we've ever had. */ unsigned int num, max; @@ -142,10 +145,10 @@ drop: static void try_fill_recv(struct virtnet_info *vi) { struct sk_buff *skb; - struct scatterlist sg[1+MAX_SKB_FRAGS]; + struct scatterlist sg[2+MAX_SKB_FRAGS]; int num, err; - sg_init_table(sg, 1+MAX_SKB_FRAGS); + sg_init_table(sg, 2+MAX_SKB_FRAGS); for (;;) { skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN); if (unlikely(!skb)) @@ -221,23 +224,22 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) { pr_debug("Sent skb %p\n", skb); __skb_unlink(skb, &vi->send); - vi->dev->stats.tx_bytes += len; + vi->dev->stats.tx_bytes += skb->len; vi->dev->stats.tx_packets++; kfree_skb(skb); } } -static int start_xmit(struct sk_buff *skb, struct net_device *dev) +static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) { - struct virtnet_info *vi = netdev_priv(dev); - int num, err; - struct scatterlist sg[1+MAX_SKB_FRAGS]; + int num; + struct scatterlist sg[2+MAX_SKB_FRAGS]; struct virtio_net_hdr *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; - sg_init_table(sg, 1+MAX_SKB_FRAGS); + sg_init_table(sg, 2+MAX_SKB_FRAGS); - pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb, + pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5]); @@ -272,30 +274,51 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev) vnet_hdr_to_sg(sg, skb); num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; - __skb_queue_head(&vi->send, skb); + + return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); +} + +static int start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct virtnet_info *vi = netdev_priv(dev); again: /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(vi); - err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); - if (err) { - pr_debug("%s: virtio not prepared to send\n", dev->name); - netif_stop_queue(dev); - - /* Activate callback for using skbs: if this returns false it - * means some were used in the meantime. */ - if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { - vi->svq->vq_ops->disable_cb(vi->svq); - netif_start_queue(dev); - goto again; + + /* If we has a buffer left over from last time, send it now. */ + if (vi->last_xmit_skb) { + if (xmit_skb(vi, vi->last_xmit_skb) != 0) { + /* Drop this skb: we only queue one. */ + vi->dev->stats.tx_dropped++; + kfree_skb(skb); + goto stop_queue; } - __skb_unlink(skb, &vi->send); + vi->last_xmit_skb = NULL; + } - return NETDEV_TX_BUSY; + /* Put new one in send queue and do transmit */ + __skb_queue_head(&vi->send, skb); + if (xmit_skb(vi, skb) != 0) { + vi->last_xmit_skb = skb; + goto stop_queue; } +done: vi->svq->vq_ops->kick(vi->svq); - - return 0; + return NETDEV_TX_OK; + +stop_queue: + pr_debug("%s: virtio not prepared to send\n", dev->name); + netif_stop_queue(dev); + + /* Activate callback for using skbs: if this returns false it + * means some were used in the meantime. */ + if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { + vi->svq->vq_ops->disable_cb(vi->svq); + netif_start_queue(dev); + goto again; + } + goto done; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -355,17 +378,26 @@ static int virtnet_probe(struct virtio_device *vdev) SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ - if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) { + if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; - if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) { + if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { dev->features |= NETIF_F_TSO | NETIF_F_UFO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } + /* Individual feature bits: what can host handle? */ + if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) + dev->features |= NETIF_F_TSO; + if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) + dev->features |= NETIF_F_TSO6; + if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) + dev->features |= NETIF_F_TSO_ECN; + if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) + dev->features |= NETIF_F_UFO; } /* Configuration may specify what MAC to use. Otherwise random. */ - if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) { + if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) { vdev->config->get(vdev, offsetof(struct virtio_net_config, mac), dev->dev_addr, dev->addr_len); @@ -454,7 +486,15 @@ static struct virtio_device_id id_table[] = { { 0 }, }; +static unsigned int features[] = { + VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, + VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_ECN, +}; + static struct virtio_driver virtio_net = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 63abfd72542d..e03eef2f2282 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 0f8aca8a4d43..249e18053d5f 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/Makefile b/drivers/net/wireless/Makefile index c2642bc1d49b..2c343aae38d4 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -56,7 +56,7 @@ obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o -obj-$(CONFIG_IWLCORE) += iwlwifi/ +obj-$(CONFIG_IWLWIFI) += iwlwifi/ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54/ diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 932d6b1c9d0b..45f47c1c0a35 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3657,7 +3657,7 @@ void mpi_receive_802_11 (struct airo_info *ai) ptr += hdrlen; if (hdrlen == 24) ptr += 6; - gap = le16_to_cpu(get_unaligned((__le16 *)ptr)); + gap = get_unaligned_le16(ptr); ptr += sizeof(__le16); if (gap) { if (gap <= 8) @@ -4347,24 +4347,28 @@ static int proc_config_open( struct inode *inode, struct file *file ); static int proc_wepkey_open( struct inode *inode, struct file *file ); static const struct file_operations proc_statsdelta_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_statsdelta_open, .release = proc_close }; static const struct file_operations proc_stats_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_stats_open, .release = proc_close }; static const struct file_operations proc_status_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_status_open, .release = proc_close }; static const struct file_operations proc_SSID_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_SSID_open, @@ -4372,6 +4376,7 @@ static const struct file_operations proc_SSID_ops = { }; static const struct file_operations proc_BSSList_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_BSSList_open, @@ -4379,6 +4384,7 @@ static const struct file_operations proc_BSSList_ops = { }; static const struct file_operations proc_APList_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_APList_open, @@ -4386,6 +4392,7 @@ static const struct file_operations proc_APList_ops = { }; static const struct file_operations proc_config_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_config_open, @@ -4393,6 +4400,7 @@ static const struct file_operations proc_config_ops = { }; static const struct file_operations proc_wepkey_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_wepkey_open, @@ -4411,10 +4419,6 @@ struct proc_data { void (*on_close) (struct inode *, struct file *); }; -#ifndef SETPROC_OPS -#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops) -#endif - static int setup_proc_entry( struct net_device *dev, struct airo_info *apriv ) { struct proc_dir_entry *entry; @@ -4430,100 +4434,76 @@ static int setup_proc_entry( struct net_device *dev, apriv->proc_entry->owner = THIS_MODULE; /* Setup the StatsDelta */ - entry = create_proc_entry("StatsDelta", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("StatsDelta", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_statsdelta_ops, dev); if (!entry) goto fail_stats_delta; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_statsdelta_ops); /* Setup the Stats */ - entry = create_proc_entry("Stats", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("Stats", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_stats_ops, dev); if (!entry) goto fail_stats; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_stats_ops); /* Setup the Status */ - entry = create_proc_entry("Status", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("Status", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_status_ops, dev); if (!entry) goto fail_status; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_status_ops); /* Setup the Config */ - entry = create_proc_entry("Config", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("Config", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_config_ops, dev); if (!entry) goto fail_config; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_config_ops); /* Setup the SSID */ - entry = create_proc_entry("SSID", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("SSID", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_SSID_ops, dev); if (!entry) goto fail_ssid; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_SSID_ops); /* Setup the APList */ - entry = create_proc_entry("APList", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("APList", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_APList_ops, dev); if (!entry) goto fail_aplist; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_APList_ops); /* Setup the BSSList */ - entry = create_proc_entry("BSSList", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("BSSList", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_BSSList_ops, dev); if (!entry) goto fail_bsslist; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_BSSList_ops); /* Setup the WepKey */ - entry = create_proc_entry("WepKey", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("WepKey", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_wepkey_ops, dev); if (!entry) goto fail_wepkey; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_wepkey_ops); return 0; @@ -5625,9 +5605,9 @@ static int __init airo_init_module( void ) int have_isa_dev = 0; #endif - airo_entry = create_proc_entry("aironet", + airo_entry = create_proc_entry("driver/aironet", S_IFDIR | airo_perm, - proc_root_driver); + NULL); if (airo_entry) { airo_entry->uid = proc_uid; @@ -5651,7 +5631,7 @@ static int __init airo_init_module( void ) airo_print_info("", "Finished probing for PCI adapters"); if (i) { - remove_proc_entry("aironet", proc_root_driver); + remove_proc_entry("driver/aironet", NULL); return i; } #endif @@ -5673,7 +5653,7 @@ static void __exit airo_cleanup_module( void ) #ifdef CONFIG_PCI pci_unregister_driver(&airo_driver); #endif - remove_proc_entry("aironet", proc_root_driver); + remove_proc_entry("driver/aironet", NULL); } /* diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index e18305b781c9..4e5c8fc35200 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -58,10 +58,6 @@ #include "reg.h" #include "debug.h" -/* unaligned little endian access */ -#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) -#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) - enum { ATH_LED_TX, ATH_LED_RX, @@ -2909,9 +2905,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (!mclist) break; /* calculate XOR of eight 6-bit values */ - val = LE_READ_4(mclist->dmi_addr + 0); + val = get_unaligned_le32(mclist->dmi_addr + 0); pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = LE_READ_4(mclist->dmi_addr + 3); + val = get_unaligned_le32(mclist->dmi_addr + 3); pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; pos &= 0x3f; mfilt[pos / 32] |= (1 << (pos % 32)); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4bf8a99099fe..8c24cd72aaca 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2171,7 +2171,7 @@ static int b43_write_initvals(struct b43_wldev *dev, goto err_format; array_size -= sizeof(iv->data.d32); - value = be32_to_cpu(get_unaligned(&iv->data.d32)); + value = get_unaligned_be32(&iv->data.d32); b43_write32(dev, offset, value); iv = (const struct b43_iv *)((const uint8_t *)iv + diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ef829ee8ffd4..14a5eea2573e 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1720,7 +1720,7 @@ static int b43legacy_write_initvals(struct b43legacy_wldev *dev, goto err_format; array_size -= sizeof(iv->data.d32); - value = be32_to_cpu(get_unaligned(&iv->data.d32)); + value = get_unaligned_be32(&iv->data.d32); b43legacy_write32(dev, offset, value); iv = (const struct b43legacy_iv *)((const uint8_t *)iv + diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index c4e631d14bfe..d5b7a76fcaad 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,6 +1,15 @@ +config IWLWIFI + bool + default n + 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 @@ -9,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" @@ -50,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 @@ -106,6 +111,9 @@ config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" 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: @@ -137,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/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 598e4eef4f40..d3406830c8e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -554,40 +554,36 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, iwl3945_rt->rt_hdr.it_pad = 0; /* total header + data */ - put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)), - &iwl3945_rt->rt_hdr.it_len); + put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len); /* Indicate all the fields we add to the radiotap header */ - put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)), - &iwl3945_rt->rt_hdr.it_present); + put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA), + &iwl3945_rt->rt_hdr.it_present); /* Zero the flags, we'll add to them as we go */ iwl3945_rt->rt_flags = 0; - put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf); + put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf); iwl3945_rt->rt_dbmsignal = signal; iwl3945_rt->rt_dbmnoise = noise; /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz); + put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz); if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ), + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, &iwl3945_rt->rt_chbitmask); else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ), + put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, &iwl3945_rt->rt_chbitmask); else /* 802.11g */ - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ), + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, &iwl3945_rt->rt_chbitmask); if (rate == -1) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e72c97a0d6c1..1a409fcc80d3 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -522,7 +522,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo)); + beaconsize = get_unaligned_le16(*pbeaconinfo); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index bced3fe1cf8a..5dd23c93497d 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/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index e34675c2f8fc..5316074f39f0 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -545,11 +545,11 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, * be padded. Unaligned access might also happen if the length_info * structure is not present. */ - if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG)) + if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG) { unsigned int l, k, n; for (i = 0, l = 0;; i++) { - k = le16_to_cpu(get_unaligned(&length_info->length[i])); + k = get_unaligned_le16(&length_info->length[i]); if (k == 0) return; n = l+k; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 24640726f8bb..57e1f495b9fc 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1062,7 +1062,7 @@ static int yellowfin_rx(struct net_device *dev) buf_addr = rx_skb->data; data_size = (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status)) & 0xffff; - frame_status = le16_to_cpu(get_unaligned((__le16*)&(buf_addr[data_size - 2]))); + frame_status = get_unaligned_le16(&(buf_addr[data_size - 2])); if (yellowfin_debug > 4) printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n", frame_status); diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index e07492be1f4a..208dd12825bc 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/nubus.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/module.h> @@ -28,38 +29,36 @@ #include <asm/byteorder.h> static int -get_nubus_dev_info(char *buf, char **start, off_t pos, int count) +nubus_devices_proc_show(struct seq_file *m, void *v) { struct nubus_dev *dev = nubus_devices; - off_t at = 0; - int len, cnt; - cnt = 0; - while (dev && count > cnt) { - len = sprintf(buf, "%x\t%04x %04x %04x %04x", + while (dev) { + seq_printf(m, "%x\t%04x %04x %04x %04x", dev->board->slot, dev->category, dev->type, dev->dr_sw, dev->dr_hw); - len += sprintf(buf+len, - "\t%08lx", - dev->board->slot_addr); - buf[len++] = '\n'; - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - } + seq_printf(m, "\t%08lx\n", dev->board->slot_addr); dev = dev->next; } - return (count > cnt) ? cnt : count; + return 0; +} + +static int nubus_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, nubus_devices_proc_show, NULL); } +static const struct file_operations nubus_devices_proc_fops = { + .owner = THIS_MODULE, + .open = nubus_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static struct proc_dir_entry *proc_bus_nubus_dir; static void nubus_proc_subdir(struct nubus_dev* dev, @@ -171,8 +170,7 @@ void __init nubus_proc_init(void) { if (!MACH_IS_MAC) return; - proc_bus_nubus_dir = proc_mkdir("nubus", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_nubus_dir, - get_nubus_dev_info); + proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); + proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); proc_bus_nubus_add_devices(); } diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b07ba2a14119..9304c4555079 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -491,7 +491,7 @@ typedef enum { */ void sync_buffer(int cpu) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu]; + struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); struct mm_struct *mm = NULL; struct task_struct * new; unsigned long cookie = 0; diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index c93d3d2640ab..efcbf4b4579f 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -27,7 +27,7 @@ #include "buffer_sync.h" #include "oprof.h" -struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; +DEFINE_PER_CPU_SHARED_ALIGNED(struct oprofile_cpu_buffer, cpu_buffer); static void wq_sync_buffer(struct work_struct *work); @@ -39,7 +39,7 @@ void free_cpu_buffers(void) int i; for_each_online_cpu(i) - vfree(cpu_buffer[i].buffer); + vfree(per_cpu(cpu_buffer, i).buffer); } int alloc_cpu_buffers(void) @@ -49,7 +49,7 @@ int alloc_cpu_buffers(void) unsigned long buffer_size = fs_cpu_buffer_size; for_each_online_cpu(i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, cpu_to_node(i)); @@ -83,7 +83,7 @@ void start_cpu_work(void) work_enabled = 1; for_each_online_cpu(i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); /* * Spread the work by 1 jiffy per cpu so they dont all @@ -100,7 +100,7 @@ void end_cpu_work(void) work_enabled = 0; for_each_online_cpu(i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); cancel_delayed_work(&b->work); } @@ -227,7 +227,7 @@ static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf) void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, unsigned long event, int is_kernel) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; + struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); if (!backtrace_depth) { log_sample(cpu_buf, pc, is_kernel, event); @@ -254,13 +254,13 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; + struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); log_sample(cpu_buf, pc, is_kernel, event); } void oprofile_add_trace(unsigned long pc) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; + struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); if (!cpu_buf->tracing) return; diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index c66c025abe75..13588174311d 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/cache.h> +#include <linux/sched.h> struct task_struct; @@ -47,7 +48,7 @@ struct oprofile_cpu_buffer { struct delayed_work work; } ____cacheline_aligned; -extern struct oprofile_cpu_buffer cpu_buffer[]; +DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index d1f6d776e9e4..f99b28e7b79a 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -23,7 +23,7 @@ void oprofile_reset_stats(void) int i; for_each_possible_cpu(i) { - cpu_buf = &cpu_buffer[i]; + cpu_buf = &per_cpu(cpu_buffer, i); cpu_buf->sample_received = 0; cpu_buf->sample_lost_overflow = 0; cpu_buf->backtrace_aborted = 0; @@ -49,7 +49,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) return; for_each_possible_cpu(i) { - cpu_buf = &cpu_buffer[i]; + cpu_buf = &per_cpu(cpu_buffer, i); snprintf(buf, 10, "cpu%d", i); cpudir = oprofilefs_mkdir(sb, dir, buf); diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 62db3c3fe4dc..07d2a8d4498f 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1551,8 +1551,7 @@ static int __init ccio_probe(struct parisc_device *dev) { int i; struct ioc *ioc, **ioc_p = &ioc_list; - struct proc_dir_entry *info_entry, *bitmap_entry; - + ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL); if (ioc == NULL) { printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); @@ -1580,13 +1579,10 @@ static int __init ccio_probe(struct parisc_device *dev) HBA_DATA(dev->dev.platform_data)->iommu = ioc; if (ioc_count == 0) { - info_entry = create_proc_entry(MODULE_NAME, 0, proc_runway_root); - if (info_entry) - info_entry->proc_fops = &ccio_proc_info_fops; - - bitmap_entry = create_proc_entry(MODULE_NAME"-bitmap", 0, proc_runway_root); - if (bitmap_entry) - bitmap_entry->proc_fops = &ccio_proc_bitmap_fops; + proc_create(MODULE_NAME, 0, proc_runway_root, + &ccio_proc_info_fops); + proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root, + &ccio_proc_bitmap_fops); } ioc_count++; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 8c4d2c13d5f2..afc849bd3f58 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1895,7 +1895,9 @@ sba_driver_callback(struct parisc_device *dev) int i; char *version; void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE); - struct proc_dir_entry *info_entry, *bitmap_entry, *root; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *root; +#endif sba_dump_ranges(sba_addr); @@ -1973,14 +1975,8 @@ sba_driver_callback(struct parisc_device *dev) break; } - info_entry = create_proc_entry("sba_iommu", 0, root); - bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root); - - if (info_entry) - info_entry->proc_fops = &sba_proc_fops; - - if (bitmap_entry) - bitmap_entry->proc_fops = &sba_proc_bitmap_fops; + proc_create("sba_iommu", 0, root, &sba_proc_fops); + proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops); #endif parisc_vmerge_boundary = IOVP_SIZE; diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 54a6ef72906e..0338b0912674 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 0e77ae2b71a0..e6a7e847ee80 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 a85808938205..e0c2a4584ec6 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); @@ -3082,6 +3082,7 @@ static struct pci_driver parport_pc_pci_driver; static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;} #endif /* CONFIG_PCI */ +#ifdef CONFIG_PNP static const struct pnp_device_id parport_pc_pnp_tbl[] = { /* Standard LPT Printer Port */ @@ -3148,6 +3149,9 @@ static struct pnp_driver parport_pc_pnp_driver = { .remove = parport_pc_pnp_remove, }; +#else +static struct pnp_driver parport_pc_pnp_driver; +#endif /* CONFIG_PNP */ static int __devinit parport_pc_platform_probe(struct platform_device *pdev) { diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index f14267e197dd..8264a7680435 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -93,11 +93,10 @@ struct controller { u8 slot_device_offset; u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 ctrlcap; + u32 slot_cap; u8 cap_base; struct timer_list poll_timer; volatile int cmd_busy; - spinlock_t lock; }; #define INT_BUTTON_IGNORE 0 @@ -137,13 +136,13 @@ struct controller { #define HP_SUPR_RM_SUP 0x00000020 #define EMI_PRSN 0x00020000 -#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) -#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) -#define MRL_SENS(cap) (cap & MRL_SENS_PRSN) -#define ATTN_LED(cap) (cap & ATTN_LED_PRSN) -#define PWR_LED(cap) (cap & PWR_LED_PRSN) -#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) -#define EMI(cap) (cap & EMI_PRSN) +#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) +#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) +#define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN) +#define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN) +#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) +#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) +#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) extern int pciehp_sysfs_enable_slot(struct slot *slot); extern int pciehp_sysfs_disable_slot(struct slot *slot); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index aee19f013d84..43d8ddb2d679 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -41,6 +41,7 @@ int pciehp_debug; int pciehp_poll_mode; int pciehp_poll_time; int pciehp_force; +int pciehp_slot_with_bus; struct workqueue_struct *pciehp_wq; #define DRIVER_VERSION "0.4" @@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644); module_param(pciehp_poll_mode, bool, 0644); module_param(pciehp_poll_time, int, 0644); module_param(pciehp_force, bool, 0644); +module_param(pciehp_slot_with_bus, bool, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); +MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name"); #define PCIE_MODULE_NAME "pciehp" @@ -193,8 +196,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) static void make_slot_name(struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", - slot->bus, slot->number); + if (pciehp_slot_with_bus) + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); + else + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", + slot->number); } static int init_slots(struct controller *ctrl) @@ -251,7 +258,7 @@ static int init_slots(struct controller *ctrl) goto error_info; } /* create additional sysfs entries */ - if (EMI(ctrl->ctrlcap)) { + if (EMI(ctrl)) { retval = sysfs_create_file(&hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); if (retval) { @@ -284,7 +291,7 @@ static void cleanup_slots(struct controller *ctrl) list_for_each_safe(tmp, next, &ctrl->slot_list) { slot = list_entry(tmp, struct slot, slot_list); list_del(&slot->slot_list); - if (EMI(ctrl->ctrlcap)) + if (EMI(ctrl)) sysfs_remove_file(&slot->hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); cancel_delayed_work(&slot->work); @@ -305,7 +312,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) hotplug_slot->info->attention_status = status; - if (ATTN_LED(slot->ctrl->ctrlcap)) + if (ATTN_LED(slot->ctrl)) slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -472,7 +479,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0; } - if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { + if ((POWER_CTRL(ctrl)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) goto err_out_free_ctrl_slot; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0c481f7d2ab3..0a7aa628e955 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -178,7 +178,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __func__); @@ -186,10 +186,10 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) pslot->hpc_ops->green_led_off(pslot); - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { err("%s: Issue of Set Attention Led command failed\n", __func__); @@ -214,14 +214,14 @@ static int board_added(struct slot *p_slot) __func__, p_slot->device, ctrl->slot_device_offset, p_slot->hp_slot); - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { /* Power on slot */ retval = p_slot->hpc_ops->power_on_slot(p_slot); if (retval) return retval; } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); /* Wait for ~1 second */ @@ -254,7 +254,7 @@ static int board_added(struct slot *p_slot) */ if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); return 0; @@ -279,7 +279,7 @@ static int remove_board(struct slot *p_slot) dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot); - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { /* power off slot */ retval = p_slot->hpc_ops->power_off_slot(p_slot); if (retval) { @@ -289,7 +289,7 @@ static int remove_board(struct slot *p_slot) } } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); @@ -327,7 +327,7 @@ static void pciehp_power_thread(struct work_struct *work) case POWERON_STATE: mutex_unlock(&p_slot->lock); if (pciehp_enable_slot(p_slot) && - PWR_LED(p_slot->ctrl->ctrlcap)) + PWR_LED(p_slot->ctrl)) p_slot->hpc_ops->green_led_off(p_slot); mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; @@ -409,9 +409,9 @@ static void handle_button_press_event(struct slot *p_slot) "press.\n", p_slot->name); } /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); schedule_delayed_work(&p_slot->work, 5*HZ); @@ -427,13 +427,13 @@ static void handle_button_press_event(struct slot *p_slot) dbg("%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) { - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); } else { - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_off(p_slot); } - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); info("PCI slot #%s - action canceled due to button press\n", p_slot->name); @@ -492,16 +492,16 @@ static void interrupt_event_handler(struct work_struct *work) handle_button_press_event(p_slot); break; case INT_POWER_FAULT: - if (!POWER_CTRL(ctrl->ctrlcap)) + if (!POWER_CTRL(ctrl)) break; - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_off(p_slot); break; case INT_PRESENCE_ON: case INT_PRESENCE_OFF: - if (!HP_SUPR_RM(ctrl->ctrlcap)) + if (!HP_SUPR_RM(ctrl)) break; dbg("Surprise Removal\n"); update_slot_info(p_slot); @@ -531,7 +531,7 @@ int pciehp_enable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __func__, @@ -541,7 +541,7 @@ int pciehp_enable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __func__, @@ -576,7 +576,7 @@ int pciehp_disable_slot(struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + if (!HP_SUPR_RM(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __func__, @@ -586,7 +586,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __func__, @@ -596,7 +596,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __func__, diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b4bbd07d1e39..891f81a0400c 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -221,6 +221,32 @@ static void start_int_poll_timer(struct controller *ctrl, int sec) add_timer(&ctrl->poll_timer); } +static inline int pciehp_request_irq(struct controller *ctrl) +{ + int retval, irq = ctrl->pci_dev->irq; + + /* Install interrupt polling timer. Start with 10 sec delay */ + if (pciehp_poll_mode) { + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); + return 0; + } + + /* Installs the interrupt handler */ + retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl); + if (retval) + err("Cannot get irq %d for the hotplug controller\n", irq); + return retval; +} + +static inline void pciehp_free_irq(struct controller *ctrl) +{ + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); + else + free_irq(ctrl->pci_dev->irq, ctrl); +} + static inline int pcie_wait_cmd(struct controller *ctrl) { int retval = 0; @@ -242,17 +268,15 @@ static inline int pcie_wait_cmd(struct controller *ctrl) /** * pcie_write_cmd - Issue controller command - * @slot: slot to which the command is issued + * @ctrl: controller to which the command is issued * @cmd: command value written to slot control register * @mask: bitmask of slot control register to be modified */ -static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) +static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) { - struct controller *ctrl = slot->ctrl; int retval = 0; u16 slot_status; u16 slot_ctrl; - unsigned long flags; mutex_lock(&ctrl->ctrl_lock); @@ -270,24 +294,24 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) __func__); } - spin_lock_irqsave(&ctrl->lock, flags); retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { err("%s: Cannot read SLOTCTRL register\n", __func__); - goto out_spin_unlock; + goto out; } slot_ctrl &= ~mask; - slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE); + slot_ctrl |= (cmd & mask); + /* Don't enable command completed if caller is changing it. */ + if (!(mask & CMD_CMPL_INTR_ENABLE)) + slot_ctrl |= CMD_CMPL_INTR_ENABLE; ctrl->cmd_busy = 1; + smp_mb(); retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); if (retval) err("%s: Cannot write to SLOTCTRL register\n", __func__); - out_spin_unlock: - spin_unlock_irqrestore(&ctrl->lock, flags); - /* * Wait for command completion. */ @@ -467,12 +491,7 @@ static int hpc_toggle_emi(struct slot *slot) slot_cmd = EMI_CTRL; cmd_mask = EMI_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); + rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); return rc; @@ -499,12 +518,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) default: return -1; } - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); + rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -519,13 +533,7 @@ static void hpc_set_green_led_on(struct slot *slot) slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); - + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } @@ -538,12 +546,7 @@ static void hpc_set_green_led_off(struct slot *slot) slot_cmd = 0x0300; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } @@ -556,23 +559,19 @@ static void hpc_set_green_led_blink(struct slot *slot) slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); - + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } static void hpc_release_ctlr(struct controller *ctrl) { - if (pciehp_poll_mode) - del_timer(&ctrl->poll_timer); - else - free_irq(ctrl->pci_dev->irq, ctrl); + /* Mask Hot-plug Interrupt Enable */ + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) + err("%s: Cannot mask hotplut interrupt enable\n", __func__); + + /* Free interrupt handler or interrupt polling timer */ + pciehp_free_irq(ctrl); /* * If this is the last controller to be released, destroy the @@ -612,19 +611,13 @@ static int hpc_power_on_slot(struct slot * slot) cmd_mask = PWR_CTRL; /* Enable detection that we turned off at slot power-off time */ if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; - cmd_mask = cmd_mask | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; + slot_cmd |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); + cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); } - retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); + retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { err("%s: Write %x command failed!\n", __func__, slot_cmd); @@ -697,18 +690,13 @@ static int hpc_power_off_slot(struct slot * slot) * till the slot is powered on again. */ if (!pciehp_poll_mode) { - slot_cmd = (slot_cmd & - ~PWR_FAULT_DETECT_ENABLE & - ~MRL_DETECT_ENABLE & - ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE; - cmd_mask = cmd_mask | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; + slot_cmd &= ~(PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); + cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); } - retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); + retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { err("%s: Write command failed!\n", __func__); retval = -1; @@ -733,139 +721,56 @@ static int hpc_power_off_slot(struct slot * slot) static irqreturn_t pcie_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; - u16 slot_status, intr_detect, intr_loc; - u16 temp_word; - int hp_slot = 0; /* only 1 slot per PCI Express port */ - int rc = 0; - unsigned long flags; - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - return IRQ_NONE; - } - - intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | - MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); - - intr_loc = slot_status & intr_detect; - - /* Check to see if it was our interrupt */ - if ( !intr_loc ) - return IRQ_NONE; + u16 detected, intr_loc; - dbg("%s: intr_loc %x\n", __func__, intr_loc); - /* Mask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - spin_lock_irqsave(&ctrl->lock, flags); - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOT_CTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); + /* + * In order to guarantee that all interrupt events are + * serviced, we need to re-inspect Slot Status register after + * clearing what is presumed to be the last pending interrupt. + */ + intr_loc = 0; + do { + if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) { + err("%s: Cannot read SLOTSTATUS\n", __func__); return IRQ_NONE; } - dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", - __func__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & - ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); + detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | + MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | + CMD_COMPLETED); + intr_loc |= detected; + if (!intr_loc) return IRQ_NONE; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOT_STATUS register\n", - __func__); + if (pciehp_writew(ctrl, SLOTSTATUS, detected)) { + err("%s: Cannot write to SLOTSTATUS\n", __func__); return IRQ_NONE; } - dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", - __func__, slot_status); + } while (detected); - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1f; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", - __func__); - return IRQ_NONE; - } - } + dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); + /* Check Command Complete Interrupt Pending */ if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending - */ ctrl->cmd_busy = 0; + smp_mb(); wake_up_interruptible(&ctrl->queue); } + /* Check MRL Sensor Changed */ if (intr_loc & MRL_SENS_CHANGED) - pciehp_handle_switch_change(hp_slot, ctrl); + pciehp_handle_switch_change(0, ctrl); + /* Check Attention Button Pressed */ if (intr_loc & ATTN_BUTTN_PRESSED) - pciehp_handle_attention_button(hp_slot, ctrl); + pciehp_handle_attention_button(0, ctrl); + /* Check Presence Detect Changed */ if (intr_loc & PRSN_DETECT_CHANGED) - pciehp_handle_presence_change(hp_slot, ctrl); + pciehp_handle_presence_change(0, ctrl); + /* Check Power Fault Detected */ if (intr_loc & PWR_FAULT_DETECTED) - pciehp_handle_power_fault(hp_slot, ctrl); - - /* Clear all events after serving them */ - temp_word = 0x1F; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); - return IRQ_NONE; - } - /* Unmask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - spin_lock_irqsave(&ctrl->lock, flags); - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); - return IRQ_NONE; - } - - dbg("%s: Unmask Hot-plug Interrupt Enable\n", __func__); - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); - return IRQ_NONE; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOT_STATUS register\n", - __func__); - return IRQ_NONE; - } - - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1F; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS failed\n", - __func__); - return IRQ_NONE; - } - dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", - __func__, temp_word); - } + pciehp_handle_power_fault(0, ctrl); return IRQ_HANDLED; } @@ -1052,7 +957,7 @@ static struct hpc_ops pciehp_hpc_ops = { }; #ifdef CONFIG_ACPI -int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) +static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) { acpi_status status; acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); @@ -1112,7 +1017,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) break; } - err("Cannot get control of hotplug hardware for pci %s\n", + dbg("Cannot get control of hotplug hardware for pci %s\n", pci_name(dev)); kfree(string.pointer); @@ -1123,45 +1028,9 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) static int pcie_init_hardware_part1(struct controller *ctrl, struct pcie_device *dev) { - int rc; - u16 temp_word; - u32 slot_cap; - u16 slot_status; - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { - err("%s: Cannot read SLOTCAP register\n", __func__); - return -1; - } - /* Mask Hot-plug Interrupt Enable */ - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - return -1; - } - - dbg("%s: SLOTCTRL %x value read %x\n", - __func__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | - 0x00; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __func__); - return -1; - } - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - return -1; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { + err("%s: Cannot mask hotplug interrupt enable\n", __func__); return -1; } return 0; @@ -1169,205 +1038,125 @@ static int pcie_init_hardware_part1(struct controller *ctrl, int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) { - int rc; - u16 temp_word; - u16 intr_enable = 0; - u32 slot_cap; - u16 slot_status; + u16 cmd, mask; - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - goto abort; - } - - intr_enable = intr_enable | PRSN_DETECT_ENABLE; - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { - err("%s: Cannot read SLOTCAP register\n", __func__); - goto abort; + /* + * We need to clear all events before enabling hotplug interrupt + * notification mechanism in order for hotplug controler to + * generate interrupts. + */ + if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + return -1; } - if (ATTN_BUTTN(slot_cap)) - intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - - if (POWER_CTRL(slot_cap)) - intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - - if (MRL_SENS(slot_cap)) - intr_enable = intr_enable | MRL_DETECT_ENABLE; + cmd = PRSN_DETECT_ENABLE; + if (ATTN_BUTTN(ctrl)) + cmd |= ATTN_BUTTN_ENABLE; + if (POWER_CTRL(ctrl)) + cmd |= PWR_FAULT_DETECT_ENABLE; + if (MRL_SENS(ctrl)) + cmd |= MRL_DETECT_ENABLE; + if (!pciehp_poll_mode) + cmd |= HP_INTR_ENABLE; - temp_word = (temp_word & ~intr_enable) | intr_enable; + mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | + PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE; - if (pciehp_poll_mode) { - temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; - } else { - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - } - - /* - * Unmask Hot-plug Interrupt Enable for the interrupt - * notification mechanism case. - */ - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __func__); + if (pcie_write_cmd(ctrl, cmd, mask)) { + err("%s: Cannot enable software notification\n", __func__); goto abort; } - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - goto abort_disable_intr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); - goto abort_disable_intr; - } - if (pciehp_force) { + if (pciehp_force) dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); - } else { - rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); - if (rc) - goto abort_disable_intr; - } + else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev)) + goto abort_disable_intr; return 0; /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (!rc) { - temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - } - if (rc) + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE)) err("%s : disabling interrupts failed\n", __func__); abort: return -1; } -int pcie_init(struct controller *ctrl, struct pcie_device *dev) +static inline void dbg_ctrl(struct controller *ctrl) { - int rc; - u16 cap_reg; - u32 slot_cap; - int cap_base; - u16 slot_status, slot_ctrl; - struct pci_dev *pdev; - - pdev = dev->port; - ctrl->pci_dev = pdev; /* save pci_dev in context */ - - dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", - __func__, pdev->vendor, pdev->device); + int i; + u16 reg16; + struct pci_dev *pdev = ctrl->pci_dev; - cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (cap_base == 0) { - dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __func__); - goto abort; - } + if (!pciehp_debug) + return; - ctrl->cap_base = cap_base; + dbg("Hotplug Controller:\n"); + dbg(" Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", pci_name(pdev), pdev->irq); + dbg(" Vendor ID : 0x%04x\n", pdev->vendor); + dbg(" Device ID : 0x%04x\n", pdev->device); + dbg(" Subsystem ID : 0x%04x\n", pdev->subsystem_device); + dbg(" Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor); + dbg(" PCIe Cap offset : 0x%02x\n", ctrl->cap_base); + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (!pci_resource_len(pdev, i)) + continue; + dbg(" PCI resource [%d] : 0x%llx@0x%llx\n", i, + (unsigned long long)pci_resource_len(pdev, i), + (unsigned long long)pci_resource_start(pdev, i)); + } + dbg("Slot Capabilities : 0x%08x\n", ctrl->slot_cap); + dbg(" Physical Slot Number : %d\n", ctrl->first_slot); + dbg(" Attention Button : %3s\n", ATTN_BUTTN(ctrl) ? "yes" : "no"); + dbg(" Power Controller : %3s\n", POWER_CTRL(ctrl) ? "yes" : "no"); + dbg(" MRL Sensor : %3s\n", MRL_SENS(ctrl) ? "yes" : "no"); + dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no"); + dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); + dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); + dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); + pciehp_readw(ctrl, SLOTSTATUS, ®16); + dbg("Slot Status : 0x%04x\n", reg16); + pciehp_readw(ctrl, SLOTSTATUS, ®16); + dbg("Slot Control : 0x%04x\n", reg16); +} - dbg("%s: pcie_cap_base %x\n", __func__, cap_base); +int pcie_init(struct controller *ctrl, struct pcie_device *dev) +{ + u32 slot_cap; + struct pci_dev *pdev = dev->port; - rc = pciehp_readw(ctrl, CAPREG, &cap_reg); - if (rc) { - err("%s: Cannot read CAPREG register\n", __func__); - goto abort; - } - dbg("%s: CAPREG offset %x cap_reg %x\n", - __func__, ctrl->cap_base + CAPREG, cap_reg); - - if (((cap_reg & SLOT_IMPL) == 0) || - (((cap_reg & DEV_PORT_TYPE) != 0x0040) - && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not " - "connected to a slot\n", __func__); + ctrl->pci_dev = pdev; + ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!ctrl->cap_base) { + err("%s: Cannot find PCI Express capability\n", __func__); goto abort; } - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { + if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) { err("%s: Cannot read SLOTCAP register\n", __func__); goto abort; } - dbg("%s: SLOTCAP offset %x slot_cap %x\n", - __func__, ctrl->cap_base + SLOTCAP, slot_cap); - - if (!(slot_cap & HP_CAP)) { - dbg("%s : This slot is not hot-plug capable\n", __func__); - goto abort; - } - /* For debugging purpose */ - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - goto abort; - } - dbg("%s: SLOTSTATUS offset %x slot_status %x\n", - __func__, ctrl->cap_base + SLOTSTATUS, slot_status); - - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - goto abort; - } - dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", - __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - - for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, - (unsigned long long)pci_resource_start(pdev, rc), - (unsigned long long)pci_resource_len(pdev, rc)); - - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + ctrl->slot_cap = slot_cap; + ctrl->first_slot = slot_cap >> 19; + ctrl->slot_device_offset = 0; + ctrl->num_slots = 1; + ctrl->hpc_ops = &pciehp_hpc_ops; mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); - spin_lock_init(&ctrl->lock); - - /* setup wait queue */ init_waitqueue_head(&ctrl->queue); + dbg_ctrl(ctrl); - /* return PCI Controller Info */ - ctrl->slot_device_offset = 0; - ctrl->num_slots = 1; - ctrl->first_slot = slot_cap >> 19; - ctrl->ctrlcap = slot_cap & 0x0000007f; + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); - rc = pcie_init_hardware_part1(ctrl, dev); - if (rc) + if (pcie_init_hardware_part1(ctrl, dev)) goto abort; - if (pciehp_poll_mode) { - /* Install interrupt polling timer. Start with 10 sec delay */ - init_timer(&ctrl->poll_timer); - start_int_poll_timer(ctrl, 10); - } else { - /* Installs the interrupt handler */ - rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, - MY_NAME, (void *)ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", - __func__, ctrl->pci_dev->irq, - atomic_read(&pciehp_num_controllers), rc); - if (rc) { - err("Can't get irq %d for the hotplug controller\n", - ctrl->pci_dev->irq); - goto abort; - } - } - dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); + if (pciehp_request_irq(ctrl)) + goto abort; /* * If this is the first controller to be initialized, @@ -1376,21 +1165,17 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) if (atomic_add_return(1, &pciehp_num_controllers) == 1) { pciehp_wq = create_singlethread_workqueue("pciehpd"); if (!pciehp_wq) { - rc = -ENOMEM; goto abort_free_irq; } } - rc = pcie_init_hardware_part2(ctrl, dev); - if (rc == 0) { - ctrl->hpc_ops = &pciehp_hpc_ops; - return 0; - } + if (pcie_init_hardware_part2(ctrl, dev)) + goto abort_free_irq; + + return 0; + abort_free_irq: - if (pciehp_poll_mode) - del_timer_sync(&ctrl->poll_timer); - else - free_irq(ctrl->pci_dev->irq, ctrl); + pciehp_free_irq(ctrl); abort: return -1; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 43816d4b3c43..1648076600fc 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -39,6 +39,7 @@ int shpchp_debug; int shpchp_poll_mode; int shpchp_poll_time; +int shpchp_slot_with_bus; struct workqueue_struct *shpchp_wq; #define DRIVER_VERSION "0.4" @@ -52,9 +53,11 @@ MODULE_LICENSE("GPL"); module_param(shpchp_debug, bool, 0644); module_param(shpchp_poll_mode, bool, 0644); module_param(shpchp_poll_time, int, 0644); +module_param(shpchp_slot_with_bus, bool, 0644); MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); +MODULE_PARM_DESC(shpchp_slot_with_bus, "Use bus number in the slot name"); #define SHPC_MODULE_NAME "shpchp" @@ -100,8 +103,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) static void make_slot_name(struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", - slot->bus, slot->number); + if (shpchp_slot_with_bus) + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); + else + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", + slot->number); } static int init_slots(struct controller *ctrl) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 26938da8f438..8c61304cbb37 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq) } } -static void msi_set_mask_bit(unsigned int irq, int flag) +static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) { struct msi_desc *entry; @@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) pos = (long)entry->mask_base; pci_read_config_dword(entry->dev, pos, &mask_bits); - mask_bits &= ~(1); - mask_bits |= flag; + mask_bits &= ~(mask); + mask_bits |= flag & mask; pci_write_config_dword(entry->dev, pos, mask_bits); } else { msi_set_enable(entry->dev, !flag); @@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) void mask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 1); + msi_set_mask_bits(irq, 1, 1); msix_flush_writes(irq); } void unmask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 0); + msi_set_mask_bits(irq, 1, 0); msix_flush_writes(irq); } @@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev) msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); if (entry->msi_attrib.maskbit) - msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); + msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask, + entry->msi_attrib.masked); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); @@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) list_for_each_entry(entry, &dev->msi_list, list) { write_msi_msg(entry->irq, &entry->msg); - msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); + msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked); } BUG_ON(list_empty(&dev->msi_list)); @@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev) pci_write_config_dword(dev, msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); + entry->msi_attrib.maskbits_mask = temp; } list_add_tail(&entry->list, &dev->msi_list); @@ -569,10 +571,9 @@ int pci_enable_msi(struct pci_dev* dev) } EXPORT_SYMBOL(pci_enable_msi); -void pci_disable_msi(struct pci_dev* dev) +void pci_msi_shutdown(struct pci_dev* dev) { struct msi_desc *entry; - int default_irq; if (!pci_msi_enable || !dev || !dev->msi_enabled) return; @@ -583,15 +584,31 @@ void pci_disable_msi(struct pci_dev* dev) BUG_ON(list_empty(&dev->msi_list)); entry = list_entry(dev->msi_list.next, struct msi_desc, list); - if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { - return; + /* Return the the pci reset with msi irqs unmasked */ + if (entry->msi_attrib.maskbit) { + u32 mask = entry->msi_attrib.maskbits_mask; + msi_set_mask_bits(dev->irq, mask, ~mask); } - - default_irq = entry->msi_attrib.default_irq; - msi_free_irqs(dev); + if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + return; /* Restore dev->irq to its default pin-assertion irq */ - dev->irq = default_irq; + dev->irq = entry->msi_attrib.default_irq; +} +void pci_disable_msi(struct pci_dev* dev) +{ + struct msi_desc *entry; + + if (!pci_msi_enable || !dev || !dev->msi_enabled) + return; + + pci_msi_shutdown(dev); + + entry = list_entry(dev->msi_list.next, struct msi_desc, list); + if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + return; + + msi_free_irqs(dev); } EXPORT_SYMBOL(pci_disable_msi); @@ -684,7 +701,7 @@ static void msix_free_all_irqs(struct pci_dev *dev) msi_free_irqs(dev); } -void pci_disable_msix(struct pci_dev* dev) +void pci_msix_shutdown(struct pci_dev* dev) { if (!pci_msi_enable || !dev || !dev->msix_enabled) return; @@ -692,6 +709,13 @@ void pci_disable_msix(struct pci_dev* dev) msix_set_enable(dev, 0); pci_intx_for_msi(dev, 1); dev->msix_enabled = 0; +} +void pci_disable_msix(struct pci_dev* dev) +{ + if (!pci_msi_enable || !dev || !dev->msix_enabled) + return; + + pci_msix_shutdown(dev); msix_free_all_irqs(dev); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e8d94fafc280..72cf61ed8f96 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -360,6 +360,8 @@ static void pci_device_shutdown(struct device *dev) if (drv && drv->shutdown) drv->shutdown(pci_dev); + pci_msi_shutdown(pci_dev); + pci_msix_shutdown(pci_dev); } /** diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 25b04fb2517d..5a0c6ad53f8e 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -33,7 +33,7 @@ source "drivers/pci/pcie/aer/Kconfig" config PCIEASPM bool "PCI Express ASPM support(Experimental)" depends on PCI && EXPERIMENTAL && PCIEPORTBUS - default y + default n help This enables PCI Express ASPM (Active State Power Management) and Clock Power Management. ASPM supports state L0/L0s/L1. diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 96ac54072f6f..d39a78dbd026 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -31,7 +31,7 @@ int aer_osc_setup(struct pcie_device *pciedev) { acpi_status status = AE_NOT_FOUND; struct pci_dev *pdev = pciedev->port; - acpi_handle handle = 0; + acpi_handle handle = NULL; if (acpi_pci_disabled) return -1; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f991359f0c36..4a55bf380957 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev) * reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size(struct pci_dev *dev) +int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix) { int pos; u32 status; + if (!check_exp_pcix) + goto skip; + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (!pos) { pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); @@ -858,6 +861,7 @@ int pci_cfg_space_size(struct pci_dev *dev) goto fail; } + skip: if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL) goto fail; if (status == 0xffffffff) @@ -869,6 +873,11 @@ int pci_cfg_space_size(struct pci_dev *dev) return PCI_CFG_SPACE_SIZE; } +int pci_cfg_space_size(struct pci_dev *dev) +{ + return pci_cfg_space_size_ext(dev, 1); +} + static void pci_release_bus_bridge_dev(struct device *dev) { kfree(dev); @@ -964,7 +973,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.release = pci_release_dev; pci_dev_get(dev); - set_dev_node(&dev->dev, pcibus_to_node(bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; @@ -1080,6 +1088,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) return max; } +void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b) +{ +} + struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { @@ -1119,6 +1131,9 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err; b->bridge = get_device(dev); + if (!parent) + set_dev_node(b->bridge, pcibus_to_node(b)); + b->dev.class = &pcibus_class; b->dev.parent = b->bridge; sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus); @@ -1136,6 +1151,8 @@ struct pci_bus * pci_create_bus(struct device *parent, b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; + set_pci_bus_resources_arch_default(b); + return b; dev_create_file_err: diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index ef18fcd641e2..963a97642ae9 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -293,6 +293,7 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file) #endif /* HAVE_PCI_MMAP */ static const struct file_operations proc_bus_pci_operations = { + .owner = THIS_MODULE, .llseek = proc_bus_pci_lseek, .read = proc_bus_pci_read, .write = proc_bus_pci_write, @@ -406,11 +407,10 @@ int pci_proc_attach_device(struct pci_dev *dev) } sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir); + e = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir, + &proc_bus_pci_operations, dev); if (!e) return -ENOMEM; - e->proc_fops = &proc_bus_pci_operations; - e->data = dev; e->size = dev->cfg_size; dev->procent = e; @@ -462,6 +462,7 @@ static int proc_bus_pci_dev_open(struct inode *inode, struct file *file) return seq_open(file, &proc_bus_pci_devices_op); } static const struct file_operations proc_bus_pci_dev_operations = { + .owner = THIS_MODULE, .open = proc_bus_pci_dev_open, .read = seq_read, .llseek = seq_lseek, @@ -470,12 +471,10 @@ static const struct file_operations proc_bus_pci_dev_operations = { static int __init pci_proc_init(void) { - struct proc_dir_entry *entry; struct pci_dev *dev = NULL; - proc_bus_pci_dir = proc_mkdir("pci", proc_bus); - entry = create_proc_entry("devices", 0, proc_bus_pci_dir); - if (entry) - entry->proc_fops = &proc_bus_pci_dev_operations; + proc_bus_pci_dir = proc_mkdir("bus/pci", NULL); + proc_create("devices", 0, proc_bus_pci_dir, + &proc_bus_pci_dev_operations); proc_initialized = 1; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_proc_attach_device(dev); diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 8d8852651fd2..1b0eb5aaf650 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -38,7 +38,6 @@ config PCMCIA_DEBUG config PCMCIA tristate "16-bit PCMCIA support" select CRC32 - select HAVE_IDE default y ---help--- This option enables support for 16-bit PCMCIA cards. Most older diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c index 74e051535d6c..c78d77fd7e3b 100644 --- a/drivers/pcmcia/au1000_db1x00.c +++ b/drivers/pcmcia/au1000_db1x00.c @@ -194,7 +194,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s default: pwr |= SET_VCC_VPP(0,0,sock); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, state->Vcc, state->Vpp); break; @@ -215,7 +215,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s default: pwr |= SET_VCC_VPP(0,0,sock); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, state->Vcc, state->Vpp); break; @@ -224,7 +224,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s default: /* what's this ? */ pwr |= SET_VCC_VPP(0,0,sock); printk(KERN_ERR "%s: bad Vcc %d\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); break; } diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index b693367d38cd..75e8f8505e47 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -41,6 +41,7 @@ #include <linux/notifier.h> #include <linux/interrupt.h> #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/platform_device.h> #include <asm/io.h> @@ -71,7 +72,7 @@ extern struct au1000_pcmcia_socket au1000_pcmcia_socket[]; u32 *pcmcia_base_vaddrs[2]; extern const unsigned long mips_io_port_base; -DECLARE_MUTEX(pcmcia_sockets_lock); +static DEFINE_MUTEX(pcmcia_sockets_lock); static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = { au1x_board_init, @@ -472,7 +473,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev) struct skt_dev_info *sinfo = dev_get_drvdata(dev); int i; - down(&pcmcia_sockets_lock); + mutex_lock(&pcmcia_sockets_lock); dev_set_drvdata(dev, NULL); for (i = 0; i < sinfo->nskt; i++) { @@ -488,7 +489,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev) } kfree(sinfo); - up(&pcmcia_sockets_lock); + mutex_unlock(&pcmcia_sockets_lock); return 0; } @@ -501,13 +502,13 @@ static int au1x00_drv_pcmcia_probe(struct device *dev) { int i, ret = -ENODEV; - down(&pcmcia_sockets_lock); + mutex_lock(&pcmcia_sockets_lock); for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) { ret = au1x00_pcmcia_hw_init[i](dev); if (ret == 0) break; } - up(&pcmcia_sockets_lock); + mutex_unlock(&pcmcia_sockets_lock); return ret; } diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c index 86c0808d6a05..157e41423a0a 100644 --- a/drivers/pcmcia/au1000_pb1x00.c +++ b/drivers/pcmcia/au1000_pb1x00.c @@ -244,7 +244,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, configure->sock); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, configure->vcc, configure->vpp); break; @@ -272,7 +272,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, configure->sock); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, configure->vcc, configure->vpp); break; @@ -300,7 +300,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, configure->sock); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, configure->vcc, configure->vpp); break; @@ -309,7 +309,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) default: /* what's this ? */ pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); printk(KERN_ERR "%s: bad Vcc %d\n", - __FUNCTION__, configure->vcc); + __func__, configure->vcc); break; } @@ -353,7 +353,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) default: pcr |= SET_VCC_VPP(0,0); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, configure->vcc, configure->vpp); break; @@ -374,7 +374,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) default: pcr |= SET_VCC_VPP(0,0); printk("%s: bad Vcc/Vpp (%d:%d)\n", - __FUNCTION__, + __func__, configure->vcc, configure->vpp); break; @@ -383,7 +383,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) default: /* what's this ? */ pcr |= SET_VCC_VPP(0,0); printk(KERN_ERR "%s: bad Vcc %d\n", - __FUNCTION__, configure->vcc); + __func__, configure->vcc); break; } diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index ce9d5c44a7b5..c78ed5347510 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c @@ -56,7 +56,7 @@ #define PCMCIA_IRQ AU1000_GPIO_4 #if 0 -#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) +#define DEBUG(x, args...) printk(__func__ ": " x, ##args) #else #define DEBUG(x,args...) #endif diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 714baaeb6da1..fb2f38dc92c5 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -209,7 +209,7 @@ static void cardbus_assign_irqs(struct pci_bus *bus, int irq) } } -int cb_alloc(struct pcmcia_socket * s) +int __ref cb_alloc(struct pcmcia_socket * s) { struct pci_bus *bus = s->cb_dev->subordinate; struct pci_dev *dev; diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 06a85d7d5aa2..36379535f9da 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -402,15 +402,6 @@ EXPORT_SYMBOL(pcmcia_replace_cis); ======================================================================*/ -static inline u16 cis_get_u16(void *ptr) -{ - return le16_to_cpu(get_unaligned((__le16 *) ptr)); -} -static inline u32 cis_get_u32(void *ptr) -{ - return le32_to_cpu(get_unaligned((__le32 *) ptr)); -} - typedef struct tuple_flags { u_int link_space:4; u_int has_link:1; @@ -471,7 +462,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) /* Get indirect link from the MFC tuple */ read_cis_cache(s, LINK_SPACE(tuple->Flags), tuple->LinkOffset, 5, link); - ofs = cis_get_u32(link + 1); + ofs = get_unaligned_le32(link + 1); SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); /* Move to the next indirect link */ tuple->LinkOffset += 5; @@ -679,8 +670,8 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) if (tuple->TupleDataLen < 5) return CS_BAD_TUPLE; p = (u_char *) tuple->TupleData; - csum->addr = tuple->CISOffset + cis_get_u16(p) - 2; - csum->len = cis_get_u16(p + 2); + csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; + csum->len = get_unaligned_le16(p + 2); csum->sum = *(p + 4); return CS_SUCCESS; } @@ -691,7 +682,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - link->addr = cis_get_u32(tuple->TupleData); + link->addr = get_unaligned_le32(tuple->TupleData); return CS_SUCCESS; } @@ -710,7 +701,7 @@ static int parse_longlink_mfc(tuple_t *tuple, return CS_BAD_TUPLE; for (i = 0; i < link->nfn; i++) { link->fn[i].space = *p; p++; - link->fn[i].addr = cis_get_u32(p); + link->fn[i].addr = get_unaligned_le32(p); p += 4; } return CS_SUCCESS; @@ -800,8 +791,8 @@ static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - m->manf = cis_get_u16(tuple->TupleData); - m->card = cis_get_u16(tuple->TupleData + 2); + m->manf = get_unaligned_le16(tuple->TupleData); + m->card = get_unaligned_le16(tuple->TupleData + 2); return CS_SUCCESS; } @@ -1100,7 +1091,7 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x20: entry->mem.nwin = 1; - entry->mem.win[0].len = cis_get_u16(p) << 8; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; entry->mem.win[0].card_addr = 0; entry->mem.win[0].host_addr = 0; p += 2; @@ -1108,8 +1099,8 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x40: entry->mem.nwin = 1; - entry->mem.win[0].len = cis_get_u16(p) << 8; - entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; + entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8; entry->mem.win[0].host_addr = 0; p += 4; if (p > q) return CS_BAD_TUPLE; @@ -1146,7 +1137,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) p = (u_char *)tuple->TupleData; bar->attr = *p; p += 2; - bar->size = cis_get_u32(p); + bar->size = get_unaligned_le32(p); return CS_SUCCESS; } @@ -1159,7 +1150,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) return CS_BAD_TUPLE; config->last_idx = *(++p); p++; - config->base = cis_get_u32(p); + config->base = get_unaligned_le32(p); config->subtuples = tuple->TupleDataLen - 6; return CS_SUCCESS; } @@ -1275,7 +1266,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) v2->vers = p[0]; v2->comply = p[1]; - v2->dindex = cis_get_u16(p +2 ); + v2->dindex = get_unaligned_le16(p +2 ); v2->vspec8 = p[6]; v2->vspec9 = p[7]; v2->nhdr = p[8]; @@ -1316,8 +1307,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) fmt->type = p[0]; fmt->edc = p[1]; - fmt->offset = cis_get_u32(p + 2); - fmt->length = cis_get_u32(p + 6); + fmt->offset = get_unaligned_le32(p + 2); + fmt->length = get_unaligned_le32(p + 6); return CS_SUCCESS; } diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 56230dbd347a..29276bd28295 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -652,6 +652,9 @@ static int pccardd(void *__skt) complete(&skt->thread_done); return 0; } + ret = pccard_sysfs_add_socket(&skt->dev); + if (ret) + dev_warn(&skt->dev, "err %d adding socket attributes\n", ret); add_wait_queue(&skt->thread_wait, &wait); complete(&skt->thread_done); @@ -694,6 +697,7 @@ static int pccardd(void *__skt) remove_wait_queue(&skt->thread_wait, &wait); /* remove from the device core */ + pccard_sysfs_remove_socket(&skt->dev); device_unregister(&skt->dev); return 0; @@ -940,20 +944,13 @@ EXPORT_SYMBOL(pcmcia_socket_class); static int __init init_pcmcia_cs(void) { - int ret; - init_completion(&pcmcia_unload); - ret = class_register(&pcmcia_socket_class); - if (ret) - return (ret); - return class_interface_register(&pccard_sysfs_interface); + return class_register(&pcmcia_socket_class); } static void __exit exit_pcmcia_cs(void) { - class_interface_unregister(&pccard_sysfs_interface); class_unregister(&pcmcia_socket_class); - wait_for_completion(&pcmcia_unload); } diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 9fa207e3c7b3..e7d5d141f24d 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -121,7 +121,8 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, void release_resource_db(struct pcmcia_socket *s); /* In socket_sysfs.c */ -extern struct class_interface pccard_sysfs_interface; +extern int pccard_sysfs_add_socket(struct device *dev); +extern void pccard_sysfs_remove_socket(struct device *dev); /* In cs.c */ extern struct rw_semaphore pcmcia_socket_list_rwsem; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 5a85871f5ee9..e40775443d04 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1520,7 +1520,7 @@ static void pcmcia_bus_remove_socket(struct device *dev, /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ -static struct class_interface pcmcia_bus_interface = { +static struct class_interface pcmcia_bus_interface __refdata = { .class = &pcmcia_socket_class, .add_dev = &pcmcia_bus_add_socket, .remove_dev = &pcmcia_bus_remove_socket, diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index e54ecc580d9e..e13618656ff7 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -53,7 +53,7 @@ static int i82092aa_socket_resume (struct pci_dev *dev) } #endif -static struct pci_driver i82092aa_pci_drv = { +static struct pci_driver i82092aa_pci_driver = { .name = "i82092aa", .id_table = i82092aa_pci_ids, .probe = i82092aa_pci_probe, @@ -714,13 +714,13 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_ static int i82092aa_module_init(void) { - return pci_register_driver(&i82092aa_pci_drv); + return pci_register_driver(&i82092aa_pci_driver); } static void i82092aa_module_exit(void) { enter("i82092aa_module_exit"); - pci_unregister_driver(&i82092aa_pci_drv); + pci_unregister_driver(&i82092aa_pci_driver); if (sockets[0].io_base>0) release_region(sockets[0].io_base, 2); leave("i82092aa_module_exit"); diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index bb6db3a582b2..46314b420765 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -153,7 +153,7 @@ omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) static int omap_cf_ss_suspend(struct pcmcia_socket *s) { - pr_debug("%s: %s\n", driver_name, __FUNCTION__); + pr_debug("%s: %s\n", driver_name, __func__); return omap_cf_set_socket(s, &dead_socket); } diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 27523c5f4dad..5f186abca108 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -787,7 +787,7 @@ void __init pcmcia_setup_ioctl(void) { major_dev = i; #ifdef CONFIG_PROC_FS - proc_pccard = proc_mkdir("pccard", proc_bus); + proc_pccard = proc_mkdir("bus/pccard", NULL); if (proc_pccard) create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); #endif @@ -798,7 +798,7 @@ void __exit pcmcia_cleanup_ioctl(void) { #ifdef CONFIG_PROC_FS if (proc_pccard) { remove_proc_entry("drivers", proc_pccard); - remove_proc_entry("pccard", proc_bus); + remove_proc_entry("bus/pccard", NULL); } #endif if (major_dev != -1) diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index abc10fe49bd8..8bed1dab9039 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -778,7 +778,7 @@ static struct pci_device_id pd6729_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, pd6729_pci_ids); -static struct pci_driver pd6729_pci_drv = { +static struct pci_driver pd6729_pci_driver = { .name = "pd6729", .id_table = pd6729_pci_ids, .probe = pd6729_pci_probe, @@ -791,12 +791,12 @@ static struct pci_driver pd6729_pci_drv = { static int pd6729_module_init(void) { - return pci_register_driver(&pd6729_pci_drv); + return pci_register_driver(&pd6729_pci_driver); } static void pd6729_module_exit(void) { - pci_unregister_driver(&pd6729_pci_drv); + pci_unregister_driver(&pd6729_pci_driver); } module_init(pd6729_module_init); diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index 4a05802213c8..881ec8a8e389 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -87,7 +87,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); ret = -1; } @@ -104,7 +104,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, pa_dwr_set |= GPIO_A0; else { printk(KERN_ERR "%s(): unrecognized Vpp %u\n", - __FUNCTION__, state->Vpp); + __func__, state->Vpp); ret = -1; break; } @@ -128,14 +128,14 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); ret = -1; break; } if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", - __FUNCTION__, state->Vpp); + __func__, state->Vpp); ret = -1; break; } diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 6fa5eaaab8af..145b85e0f02c 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -99,7 +99,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, case 50: power |= MST_PCMCIA_PWR_VCC_50; break; default: printk(KERN_ERR "%s(): bad Vcc %u\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); ret = -1; } @@ -111,7 +111,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, power |= MST_PCMCIA_PWR_VPP_VCC; } else { printk(KERN_ERR "%s(): bad Vpp %u\n", - __FUNCTION__, state->Vpp); + __func__, state->Vpp); ret = -1; } } diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index a8d100707721..0fcf763b9175 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -1045,7 +1045,7 @@ static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, device_remove_file(dev, *attr); } -static struct class_interface pccard_rsrc_interface = { +static struct class_interface pccard_rsrc_interface __refdata = { .class = &pcmcia_socket_class, .add_dev = &pccard_sysfs_add_rsrc, .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc), diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index 7c57fdd3c8d7..ce133ce81c10 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -66,14 +66,14 @@ assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_stat case 50: printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); + __func__); case 33: /* Can only apply 3.3V to the CF slot. */ mask = ASSABET_BCR_CF_PWR; break; default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __func__, state->Vcc); return -1; } diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c index 62bfc7566ec2..607c3f326eca 100644 --- a/drivers/pcmcia/sa1100_badge4.c +++ b/drivers/pcmcia/sa1100_badge4.c @@ -82,14 +82,14 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state case 0: if ((state->Vcc != 0) && (state->Vcc != badge4_pcmvcc)) { - complain_about_jumpering(__FUNCTION__, "pcmvcc", + complain_about_jumpering(__func__, "pcmvcc", badge4_pcmvcc, state->Vcc); // Apply power regardless of the jumpering. // return -1; } if ((state->Vpp != 0) && (state->Vpp != badge4_pcmvpp)) { - complain_about_jumpering(__FUNCTION__, "pcmvpp", + complain_about_jumpering(__func__, "pcmvpp", badge4_pcmvpp, state->Vpp); return -1; } @@ -98,7 +98,7 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state case 1: if ((state->Vcc != 0) && (state->Vcc != badge4_cfvcc)) { - complain_about_jumpering(__FUNCTION__, "cfvcc", + complain_about_jumpering(__func__, "cfvcc", badge4_cfvcc, state->Vcc); return -1; } @@ -143,7 +143,7 @@ int pcmcia_badge4_init(struct device *dev) if (machine_is_badge4()) { printk(KERN_INFO "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", - __FUNCTION__, + __func__, badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2); diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index 549a1529fe35..7c3951a2675d 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -63,7 +63,7 @@ cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); return -1; } diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index 6284c35dabc6..2167e6714d2d 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -42,7 +42,7 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s unsigned int pa_dwr_mask, pa_dwr_set; int ret; -printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, +printk("%s(): config socket %d vcc %d vpp %d\n", __func__, skt->nr, state->Vcc, state->Vpp); switch (skt->nr) { @@ -74,7 +74,7 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): slot cannot support VPP %u\n", - __FUNCTION__, state->Vpp); + __func__, state->Vpp); return -1; } diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index 5bc9e9532b9d..687492fcd5b4 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -59,7 +59,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta ncr_set = NCR_A0VPP; else { printk(KERN_ERR "%s(): unrecognized VPP %u\n", - __FUNCTION__, state->Vpp); + __func__, state->Vpp); return -1; } break; @@ -71,7 +71,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", - __FUNCTION__, state->Vpp); + __func__, state->Vpp); return -1; } break; diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c index 9456f5478d09..494912fccc0d 100644 --- a/drivers/pcmcia/sa1100_shannon.c +++ b/drivers/pcmcia/sa1100_shannon.c @@ -73,19 +73,19 @@ shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, { switch (state->Vcc) { case 0: /* power off */ - printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __FUNCTION__); + printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __func__); break; case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __FUNCTION__); + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __func__); case 33: break; default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); return -1; } - printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __FUNCTION__); + printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __func__); /* Silently ignore Vpp, output enable, speaker enable. */ diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index 04d6f7f75f78..42567de894b9 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -90,7 +90,7 @@ simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", - __FUNCTION__, state->Vcc); + __func__, state->Vcc); clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); local_irq_restore(flags); return -1; diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index aa7779d89752..420a77540f41 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -37,6 +37,7 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/mm.h> +#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/spinlock.h> @@ -353,7 +354,7 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m (map->flags&MAP_PREFETCH)?"PREFETCH ":""); if (map->map >= MAX_IO_WIN) { - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, + printk(KERN_ERR "%s(): map (%d) out of range\n", __func__, map->map); return -1; } @@ -578,7 +579,7 @@ EXPORT_SYMBOL(soc_pcmcia_enable_irqs); LIST_HEAD(soc_pcmcia_sockets); -DECLARE_MUTEX(soc_pcmcia_sockets_lock); +static DEFINE_MUTEX(soc_pcmcia_sockets_lock); static const char *skt_names[] = { "PCMCIA socket 0", @@ -601,11 +602,11 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) struct cpufreq_freqs *freqs = data; int ret = 0; - down(&soc_pcmcia_sockets_lock); + mutex_lock(&soc_pcmcia_sockets_lock); list_for_each_entry(skt, &soc_pcmcia_sockets, node) if ( skt->ops->frequency_change ) ret += skt->ops->frequency_change(skt, val, freqs); - up(&soc_pcmcia_sockets_lock); + mutex_unlock(&soc_pcmcia_sockets_lock); return ret; } @@ -642,7 +643,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops struct soc_pcmcia_socket *skt; int ret, i; - down(&soc_pcmcia_sockets_lock); + mutex_lock(&soc_pcmcia_sockets_lock); sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); if (!sinfo) { @@ -782,7 +783,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops kfree(sinfo); out: - up(&soc_pcmcia_sockets_lock); + mutex_unlock(&soc_pcmcia_sockets_lock); return ret; } @@ -793,7 +794,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev) dev_set_drvdata(dev, NULL); - down(&soc_pcmcia_sockets_lock); + mutex_lock(&soc_pcmcia_sockets_lock); for (i = 0; i < sinfo->nskt; i++) { struct soc_pcmcia_socket *skt = &sinfo->skt[i]; @@ -818,7 +819,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev) if (list_empty(&soc_pcmcia_sockets)) soc_pcmcia_cpufreq_unregister(); - up(&soc_pcmcia_sockets_lock); + mutex_unlock(&soc_pcmcia_sockets_lock); kfree(sinfo); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 6f14126889b3..1edc1da9d353 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -133,7 +133,6 @@ extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_ extern struct list_head soc_pcmcia_sockets; -extern struct semaphore soc_pcmcia_sockets_lock; extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); extern int soc_common_drv_pcmcia_remove(struct device *dev); diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index b4409002b7f8..562384d6f321 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -356,19 +356,23 @@ static ssize_t pccard_store_cis(struct kobject *kobj, } -static struct device_attribute *pccard_socket_attributes[] = { - &dev_attr_card_type, - &dev_attr_card_voltage, - &dev_attr_card_vpp, - &dev_attr_card_vcc, - &dev_attr_card_insert, - &dev_attr_card_pm_state, - &dev_attr_card_eject, - &dev_attr_card_irq_mask, - &dev_attr_available_resources_setup_done, +static struct attribute *pccard_socket_attributes[] = { + &dev_attr_card_type.attr, + &dev_attr_card_voltage.attr, + &dev_attr_card_vpp.attr, + &dev_attr_card_vcc.attr, + &dev_attr_card_insert.attr, + &dev_attr_card_pm_state.attr, + &dev_attr_card_eject.attr, + &dev_attr_card_irq_mask.attr, + &dev_attr_available_resources_setup_done.attr, NULL, }; +static const struct attribute_group socket_attrs = { + .attrs = pccard_socket_attributes, +}; + static struct bin_attribute pccard_cis_attr = { .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR }, .size = 0x200, @@ -376,35 +380,21 @@ static struct bin_attribute pccard_cis_attr = { .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct device *dev, - struct class_interface *class_intf) +int pccard_sysfs_add_socket(struct device *dev) { - struct device_attribute **attr; int ret = 0; - for (attr = pccard_socket_attributes; *attr; attr++) { - ret = device_create_file(dev, *attr); + ret = sysfs_create_group(&dev->kobj, &socket_attrs); + if (!ret) { + ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr); if (ret) - break; + sysfs_remove_group(&dev->kobj, &socket_attrs); } - if (!ret) - ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr); - return ret; } -static void __devexit pccard_sysfs_remove_socket(struct device *dev, - struct class_interface *class_intf) +void pccard_sysfs_remove_socket(struct device *dev) { - struct device_attribute **attr; - sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr); - for (attr = pccard_socket_attributes; *attr; attr++) - device_remove_file(dev, *attr); + sysfs_remove_group(&dev->kobj, &socket_attrs); } - -struct class_interface pccard_sysfs_interface = { - .class = &pcmcia_socket_class, - .add_dev = &pccard_sysfs_add_socket, - .remove_dev = __devexit_p(&pccard_sysfs_remove_socket), -}; diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 31a633f65547..4fe7c58f57e9 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -1,12 +1,78 @@ extern spinlock_t pnp_lock; void *pnp_alloc(long size); + +int pnp_register_protocol(struct pnp_protocol *protocol); +void pnp_unregister_protocol(struct pnp_protocol *protocol); + +#define PNP_EISA_ID_MASK 0x7fffffff +void pnp_eisa_id_to_string(u32 id, char *str); +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid); +struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid); + +int pnp_add_device(struct pnp_dev *dev); +struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id); int pnp_interface_attach_device(struct pnp_dev *dev); + +int pnp_add_card(struct pnp_card *card); +struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id); +void pnp_remove_card(struct pnp_card *card); +int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); +void pnp_remove_card_device(struct pnp_dev *dev); + +struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); +struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, + int priority); +int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_irq *data); +int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_dma *data); +int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_port *data); +int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_mem *data); +void pnp_init_resources(struct pnp_dev *dev); + void pnp_fixup_device(struct pnp_dev *dev); void pnp_free_option(struct pnp_option *option); int __pnp_add_device(struct pnp_dev *dev); void __pnp_remove_device(struct pnp_dev *dev); -int pnp_check_port(struct pnp_dev * dev, int idx); -int pnp_check_mem(struct pnp_dev * dev, int idx); -int pnp_check_irq(struct pnp_dev * dev, int idx); -int pnp_check_dma(struct pnp_dev * dev, int idx); +int pnp_check_port(struct pnp_dev *dev, struct resource *res); +int pnp_check_mem(struct pnp_dev *dev, struct resource *res); +int pnp_check_irq(struct pnp_dev *dev, struct resource *res); +int pnp_check_dma(struct pnp_dev *dev, struct resource *res); + +void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc); + +void pnp_init_resource(struct resource *res); + +struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev, + unsigned int type, unsigned int num); + +#define PNP_MAX_PORT 40 +#define PNP_MAX_MEM 24 +#define PNP_MAX_IRQ 2 +#define PNP_MAX_DMA 2 + +struct pnp_resource { + struct resource res; + unsigned int index; /* ISAPNP config register index */ +}; + +struct pnp_resource_table { + struct pnp_resource port[PNP_MAX_PORT]; + struct pnp_resource mem[PNP_MAX_MEM]; + struct pnp_resource dma[PNP_MAX_DMA]; + struct pnp_resource irq[PNP_MAX_IRQ]; +}; + +struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, + int flags); +struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, + int flags); +struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end, int flags); +struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end, int flags); diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index da1c9909eb44..a762a4176736 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -5,6 +5,7 @@ */ #include <linux/module.h> +#include <linux/ctype.h> #include <linux/slab.h> #include <linux/pnp.h> #include "base.h" @@ -100,19 +101,33 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv) * @id: pointer to a pnp_id structure * @card: pointer to the desired card */ -int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card) +struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) { - struct pnp_id *ptr; + struct pnp_id *dev_id, *ptr; - id->next = NULL; + dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); + if (!dev_id) + return NULL; + + dev_id->id[0] = id[0]; + dev_id->id[1] = id[1]; + dev_id->id[2] = id[2]; + dev_id->id[3] = tolower(id[3]); + dev_id->id[4] = tolower(id[4]); + dev_id->id[5] = tolower(id[5]); + dev_id->id[6] = tolower(id[6]); + dev_id->id[7] = '\0'; + + dev_id->next = NULL; ptr = card->id; while (ptr && ptr->next) ptr = ptr->next; if (ptr) - ptr->next = id; + ptr->next = dev_id; else - card->id = id; - return 0; + card->id = dev_id; + + return dev_id; } static void pnp_free_card_ids(struct pnp_card *card) @@ -136,6 +151,31 @@ static void pnp_release_card(struct device *dmdev) kfree(card); } +struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnpid) +{ + struct pnp_card *card; + struct pnp_id *dev_id; + + card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL); + if (!card) + return NULL; + + card->protocol = protocol; + card->number = id; + + card->dev.parent = &card->protocol->dev; + sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, + card->number); + + dev_id = pnp_add_card_id(card, pnpid); + if (!dev_id) { + kfree(card); + return NULL; + } + + return card; +} + static ssize_t pnp_show_card_name(struct device *dmdev, struct device_attribute *attr, char *buf) { @@ -191,9 +231,6 @@ int pnp_add_card(struct pnp_card *card) int error; struct list_head *pos, *temp; - sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, - card->number); - card->dev.parent = &card->protocol->dev; card->dev.bus = NULL; card->dev.release = &pnp_release_card; error = device_register(&card->dev); diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 7d366ca672d3..20771b7d4482 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -106,18 +106,53 @@ static void pnp_release_device(struct device *dmdev) pnp_free_option(dev->independent); pnp_free_option(dev->dependent); pnp_free_ids(dev); + kfree(dev->res); kfree(dev); } -int __pnp_add_device(struct pnp_dev *dev) +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid) { - int ret; + struct pnp_dev *dev; + struct pnp_id *dev_id; - pnp_fixup_device(dev); + dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->res = kzalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); + if (!dev->res) { + kfree(dev); + return NULL; + } + + dev->protocol = protocol; + dev->number = id; + dev->dma_mask = DMA_24BIT_MASK; + + dev->dev.parent = &dev->protocol->dev; dev->dev.bus = &pnp_bus_type; dev->dev.dma_mask = &dev->dma_mask; - dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK; + dev->dev.coherent_dma_mask = dev->dma_mask; dev->dev.release = &pnp_release_device; + + sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, + dev->number); + + dev_id = pnp_add_id(dev, pnpid); + if (!dev_id) { + kfree(dev->res); + kfree(dev); + return NULL; + } + + return dev; +} + +int __pnp_add_device(struct pnp_dev *dev) +{ + int ret; + + pnp_fixup_device(dev); dev->status = PNP_READY; spin_lock(&pnp_lock); list_add_tail(&dev->global_list, &pnp_global); @@ -145,9 +180,6 @@ int pnp_add_device(struct pnp_dev *dev) if (dev->card) return -EINVAL; - dev->dev.parent = &dev->protocol->dev; - sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, - dev->number); ret = __pnp_add_device(dev); if (ret) return ret; diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 12a1645a2e43..d3f869ee1d92 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -167,7 +167,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return error; } - if (pnp_dev->protocol && pnp_dev->protocol->suspend) + if (pnp_dev->protocol->suspend) pnp_dev->protocol->suspend(pnp_dev, state); return 0; } @@ -181,7 +181,7 @@ static int pnp_bus_resume(struct device *dev) if (!pnp_drv) return 0; - if (pnp_dev->protocol && pnp_dev->protocol->resume) + if (pnp_dev->protocol->resume) pnp_dev->protocol->resume(pnp_dev); if (pnp_can_write(pnp_dev)) { @@ -226,22 +226,36 @@ void pnp_unregister_driver(struct pnp_driver *drv) /** * pnp_add_id - adds an EISA id to the specified device - * @id: pointer to a pnp_id structure * @dev: pointer to the desired device + * @id: pointer to an EISA id string */ -int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) +struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id) { - struct pnp_id *ptr; + struct pnp_id *dev_id, *ptr; - id->next = NULL; + dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); + if (!dev_id) + return NULL; + + dev_id->id[0] = id[0]; + dev_id->id[1] = id[1]; + dev_id->id[2] = id[2]; + dev_id->id[3] = tolower(id[3]); + dev_id->id[4] = tolower(id[4]); + dev_id->id[5] = tolower(id[5]); + dev_id->id[6] = tolower(id[6]); + dev_id->id[7] = '\0'; + + dev_id->next = NULL; ptr = dev->id; while (ptr && ptr->next) ptr = ptr->next; if (ptr) - ptr->next = id; + ptr->next = dev_id; else - dev->id = id; - return 0; + dev->id = dev_id; + + return dev_id; } EXPORT_SYMBOL(pnp_register_driver); diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 982658477a58..5d9301de1778 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -248,6 +248,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); + struct resource *res; int i, ret; pnp_info_buffer_t *buffer; @@ -267,50 +268,46 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, else pnp_printf(buffer, "disabled\n"); - for (i = 0; i < PNP_MAX_PORT; i++) { - if (pnp_port_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { + if (pnp_resource_valid(res)) { pnp_printf(buffer, "io"); - if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " 0x%llx-0x%llx\n", - (unsigned long long) - pnp_port_start(dev, i), - (unsigned long long)pnp_port_end(dev, - i)); + (unsigned long long) res->start, + (unsigned long long) res->end); } } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (pnp_mem_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { + if (pnp_resource_valid(res)) { pnp_printf(buffer, "mem"); - if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " 0x%llx-0x%llx\n", - (unsigned long long) - pnp_mem_start(dev, i), - (unsigned long long)pnp_mem_end(dev, - i)); + (unsigned long long) res->start, + (unsigned long long) res->end); } } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (pnp_irq_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) { + if (pnp_resource_valid(res)) { pnp_printf(buffer, "irq"); - if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " %lld\n", - (unsigned long long)pnp_irq(dev, i)); + (unsigned long long) res->start); } } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (pnp_dma_valid(dev, i)) { + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) { + if (pnp_resource_valid(res)) { pnp_printf(buffer, "dma"); - if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED) + if (res->flags & IORESOURCE_DISABLED) pnp_printf(buffer, " disabled\n"); else pnp_printf(buffer, " %lld\n", - (unsigned long long)pnp_dma(dev, i)); + (unsigned long long) res->start); } } ret = (buffer->curr - buf); @@ -323,8 +320,10 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, const char *ubuf, size_t count) { struct pnp_dev *dev = to_pnp_dev(dmdev); + struct pnp_resource *pnp_res; char *buf = (void *)ubuf; int retval = 0; + resource_size_t start, end; if (dev->status & PNP_ATTACHED) { retval = -EBUSY; @@ -351,20 +350,20 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, if (!strnicmp(buf, "auto", 4)) { if (dev->active) goto done; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf, "clear", 5)) { if (dev->active) goto done; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); goto done; } if (!strnicmp(buf, "get", 3)) { mutex_lock(&pnp_res_mutex); if (pnp_can_read(dev)) - dev->protocol->get(dev, &dev->res); + dev->protocol->get(dev); mutex_unlock(&pnp_res_mutex); goto done; } @@ -373,7 +372,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, if (dev->active) goto done; buf += 3; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); mutex_lock(&pnp_res_mutex); while (1) { while (isspace(*buf)) @@ -382,76 +381,60 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, buf += 2; while (isspace(*buf)) ++buf; - dev->res.port_resource[nport].start = - simple_strtoul(buf, &buf, 0); + start = simple_strtoul(buf, &buf, 0); while (isspace(*buf)) ++buf; if (*buf == '-') { buf += 1; while (isspace(*buf)) ++buf; - dev->res.port_resource[nport].end = - simple_strtoul(buf, &buf, 0); + end = simple_strtoul(buf, &buf, 0); } else - dev->res.port_resource[nport].end = - dev->res.port_resource[nport].start; - dev->res.port_resource[nport].flags = - IORESOURCE_IO; - nport++; - if (nport >= PNP_MAX_PORT) - break; + end = start; + pnp_res = pnp_add_io_resource(dev, start, end, + 0); + if (pnp_res) + pnp_res->index = nport++; continue; } if (!strnicmp(buf, "mem", 3)) { buf += 3; while (isspace(*buf)) ++buf; - dev->res.mem_resource[nmem].start = - simple_strtoul(buf, &buf, 0); + start = simple_strtoul(buf, &buf, 0); while (isspace(*buf)) ++buf; if (*buf == '-') { buf += 1; while (isspace(*buf)) ++buf; - dev->res.mem_resource[nmem].end = - simple_strtoul(buf, &buf, 0); + end = simple_strtoul(buf, &buf, 0); } else - dev->res.mem_resource[nmem].end = - dev->res.mem_resource[nmem].start; - dev->res.mem_resource[nmem].flags = - IORESOURCE_MEM; - nmem++; - if (nmem >= PNP_MAX_MEM) - break; + end = start; + pnp_res = pnp_add_mem_resource(dev, start, end, + 0); + if (pnp_res) + pnp_res->index = nmem++; continue; } if (!strnicmp(buf, "irq", 3)) { buf += 3; while (isspace(*buf)) ++buf; - dev->res.irq_resource[nirq].start = - dev->res.irq_resource[nirq].end = - simple_strtoul(buf, &buf, 0); - dev->res.irq_resource[nirq].flags = - IORESOURCE_IRQ; - nirq++; - if (nirq >= PNP_MAX_IRQ) - break; + start = simple_strtoul(buf, &buf, 0); + pnp_res = pnp_add_irq_resource(dev, start, 0); + if (pnp_res) + nirq++; continue; } if (!strnicmp(buf, "dma", 3)) { buf += 3; while (isspace(*buf)) ++buf; - dev->res.dma_resource[ndma].start = - dev->res.dma_resource[ndma].end = - simple_strtoul(buf, &buf, 0); - dev->res.dma_resource[ndma].flags = - IORESOURCE_DMA; - ndma++; - if (ndma >= PNP_MAX_DMA) - break; + start = simple_strtoul(buf, &buf, 0); + pnp_res = pnp_add_dma_resource(dev, start, 0); + if (pnp_res) + pnp_res->index = ndma++; continue; } break; diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile index cac18bbfb817..3e38f06f8d78 100644 --- a/drivers/pnp/isapnp/Makefile +++ b/drivers/pnp/isapnp/Makefile @@ -5,3 +5,7 @@ isapnp-proc-$(CONFIG_PROC_FS) = proc.o obj-y := core.o compat.o $(isapnp-proc-y) + +ifeq ($(CONFIG_PNP_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 257f5d827d83..f1bccdbdeb08 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -44,6 +44,8 @@ #include <linux/mutex.h> #include <asm/io.h> +#include "../base.h" + #if 0 #define ISAPNP_REGION_OK #endif @@ -88,6 +90,14 @@ MODULE_LICENSE("GPL"); #define _LTAG_MEM32RANGE 0x85 #define _LTAG_FIXEDMEM32RANGE 0x86 +/* Logical device control and configuration registers */ + +#define ISAPNP_CFG_ACTIVATE 0x30 /* byte */ +#define ISAPNP_CFG_MEM 0x40 /* 4 * dword */ +#define ISAPNP_CFG_PORT 0x60 /* 8 * word */ +#define ISAPNP_CFG_IRQ 0x70 /* 2 * word */ +#define ISAPNP_CFG_DMA 0x74 /* 2 * byte */ + /* * Sizes of ISAPNP logical device configuration register sets. * See PNP-ISA-v1.0a.pdf, Appendix A. @@ -388,28 +398,6 @@ static void __init isapnp_skip_bytes(int count) } /* - * Parse EISA id. - */ -static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor, - unsigned short device) -{ - struct pnp_id *id; - - if (!dev) - return; - id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!id) - return; - sprintf(id->id, "%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f); - pnp_add_id(id, dev); -} - -/* * Parse logical device tag. */ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card, @@ -417,30 +405,31 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card, { unsigned char tmp[6]; struct pnp_dev *dev; + u32 eisa_id; + char id[8]; isapnp_peek(tmp, size); - dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); + eisa_id = tmp[0] | tmp[1] << 8 | tmp[2] << 16 | tmp[3] << 24; + pnp_eisa_id_to_string(eisa_id, id); + + dev = pnp_alloc_dev(&isapnp_protocol, number, id); if (!dev) return NULL; - dev->number = number; - isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]); - dev->regs = tmp[4]; + dev->card = card; - if (size > 5) - dev->regs |= tmp[5] << 8; - dev->protocol = &isapnp_protocol; dev->capabilities |= PNP_CONFIGURABLE; dev->capabilities |= PNP_READ; dev->capabilities |= PNP_WRITE; dev->capabilities |= PNP_DISABLE; - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); return dev; } /* * Add IRQ resource to resources list. */ -static void __init isapnp_parse_irq_resource(struct pnp_option *option, +static void __init isapnp_parse_irq_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[3]; @@ -457,13 +446,14 @@ static void __init isapnp_parse_irq_resource(struct pnp_option *option, irq->flags = tmp[2]; else irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_register_irq_resource(option, irq); + pnp_register_irq_resource(dev, option, irq); } /* * Add DMA resource to resources list. */ -static void __init isapnp_parse_dma_resource(struct pnp_option *option, +static void __init isapnp_parse_dma_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[2]; @@ -475,13 +465,14 @@ static void __init isapnp_parse_dma_resource(struct pnp_option *option, return; dma->map = tmp[0]; dma->flags = tmp[1]; - pnp_register_dma_resource(option, dma); + pnp_register_dma_resource(dev, option, dma); } /* * Add port resource to resources list. */ -static void __init isapnp_parse_port_resource(struct pnp_option *option, +static void __init isapnp_parse_port_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[7]; @@ -496,13 +487,14 @@ static void __init isapnp_parse_port_resource(struct pnp_option *option, port->align = tmp[5]; port->size = tmp[6]; port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } /* * Add fixed port resource to resources list. */ -static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option, +static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[3]; @@ -516,13 +508,14 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option, port->size = tmp[2]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } /* * Add memory resource to resources list. */ -static void __init isapnp_parse_mem_resource(struct pnp_option *option, +static void __init isapnp_parse_mem_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[9]; @@ -537,13 +530,14 @@ static void __init isapnp_parse_mem_resource(struct pnp_option *option, mem->align = (tmp[6] << 8) | tmp[5]; mem->size = ((tmp[8] << 8) | tmp[7]) << 8; mem->flags = tmp[0]; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } /* * Add 32-bit memory resource to resources list. */ -static void __init isapnp_parse_mem32_resource(struct pnp_option *option, +static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[17]; @@ -560,13 +554,14 @@ static void __init isapnp_parse_mem32_resource(struct pnp_option *option, mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; mem->flags = tmp[0]; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } /* * Add 32-bit fixed memory resource to resources list. */ -static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option, +static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev, + struct pnp_option *option, int size) { unsigned char tmp[9]; @@ -581,7 +576,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option, mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; mem->align = 0; mem->flags = tmp[0]; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } /* @@ -613,6 +608,8 @@ static int __init isapnp_create_device(struct pnp_card *card, unsigned char type, tmp[17]; struct pnp_option *option; struct pnp_dev *dev; + u32 eisa_id; + char id[8]; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; @@ -652,8 +649,10 @@ static int __init isapnp_create_device(struct pnp_card *card, case _STAG_COMPATDEVID: if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) { isapnp_peek(tmp, 4); - isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], - (tmp[3] << 8) | tmp[2]); + eisa_id = tmp[0] | tmp[1] << 8 | + tmp[2] << 16 | tmp[3] << 24; + pnp_eisa_id_to_string(eisa_id, id); + pnp_add_id(dev, id); compat++; size = 0; } @@ -661,13 +660,13 @@ static int __init isapnp_create_device(struct pnp_card *card, case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; - isapnp_parse_irq_resource(option, size); + isapnp_parse_irq_resource(dev, option, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; - isapnp_parse_dma_resource(option, size); + isapnp_parse_dma_resource(dev, option, size); size = 0; break; case _STAG_STARTDEP: @@ -687,17 +686,18 @@ static int __init isapnp_create_device(struct pnp_card *card, if (size != 0) goto __skip; priority = 0; + dev_dbg(&dev->dev, "end dependent options\n"); break; case _STAG_IOPORT: if (size != 7) goto __skip; - isapnp_parse_port_resource(option, size); + isapnp_parse_port_resource(dev, option, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; - isapnp_parse_fixed_port_resource(option, size); + isapnp_parse_fixed_port_resource(dev, option, size); size = 0; break; case _STAG_VENDOR: @@ -705,7 +705,7 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEMRANGE: if (size != 9) goto __skip; - isapnp_parse_mem_resource(option, size); + isapnp_parse_mem_resource(dev, option, size); size = 0; break; case _LTAG_ANSISTR: @@ -720,13 +720,13 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEM32RANGE: if (size != 17) goto __skip; - isapnp_parse_mem32_resource(option, size); + isapnp_parse_mem32_resource(dev, option, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 9) goto __skip; - isapnp_parse_fixed_mem32_resource(option, size); + isapnp_parse_fixed_mem32_resource(dev, option, size); size = 0; break; case _STAG_END: @@ -734,9 +734,8 @@ static int __init isapnp_create_device(struct pnp_card *card, isapnp_skip_bytes(size); return 1; default: - printk(KERN_ERR - "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", - type, dev->number, card->number); + dev_err(&dev->dev, "unknown tag %#x (card %i), " + "ignored\n", type, card->number); } __skip: if (size > 0) @@ -789,9 +788,8 @@ static void __init isapnp_parse_resource_map(struct pnp_card *card) isapnp_skip_bytes(size); return; default: - printk(KERN_ERR - "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", - type, card->number); + dev_err(&card->dev, "unknown tag %#x, ignored\n", + type); } __skip: if (size > 0) @@ -822,25 +820,6 @@ static unsigned char __init isapnp_checksum(unsigned char *data) } /* - * Parse EISA id for ISA PnP card. - */ -static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor, - unsigned short device) -{ - struct pnp_id *id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - - if (!id) - return; - sprintf(id->id, "%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f); - pnp_add_card_id(id, card); -} - -/* * Build device list for all present ISA PnP devices. */ static int __init isapnp_build_device_list(void) @@ -848,6 +827,8 @@ static int __init isapnp_build_device_list(void) int csn; unsigned char header[9], checksum; struct pnp_card *card; + u32 eisa_id; + char id[8]; isapnp_wait(); isapnp_key(); @@ -855,32 +836,30 @@ static int __init isapnp_build_device_list(void) isapnp_wake(csn); isapnp_peek(header, 9); checksum = isapnp_checksum(header); + eisa_id = header[0] | header[1] << 8 | + header[2] << 16 | header[3] << 24; + pnp_eisa_id_to_string(eisa_id, id); + card = pnp_alloc_card(&isapnp_protocol, csn, id); + if (!card) + continue; + #if 0 - printk(KERN_DEBUG + dev_info(&card->dev, "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3], header[4], header[5], header[6], header[7], header[8]); - printk(KERN_DEBUG "checksum = 0x%x\n", checksum); + dev_info(&card->dev, "checksum = %#x\n", checksum); #endif - if ((card = - kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL) - continue; - - card->number = csn; INIT_LIST_HEAD(&card->devices); - isapnp_parse_card_id(card, (header[1] << 8) | header[0], - (header[3] << 8) | header[2]); card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4]; isapnp_checksum_value = 0x00; isapnp_parse_resource_map(card); if (isapnp_checksum_value != 0x00) - printk(KERN_ERR - "isapnp: checksum for device %i is not valid (0x%x)\n", - csn, isapnp_checksum_value); + dev_err(&card->dev, "invalid checksum %#x\n", + isapnp_checksum_value); card->checksum = isapnp_checksum_value; - card->protocol = &isapnp_protocol; pnp_add_card(card); } @@ -947,100 +926,117 @@ EXPORT_SYMBOL(isapnp_cfg_begin); EXPORT_SYMBOL(isapnp_cfg_end); EXPORT_SYMBOL(isapnp_write_byte); -static int isapnp_read_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int isapnp_get_resources(struct pnp_dev *dev) { - int tmp, ret; + struct pnp_resource *pnp_res; + int i, ret; + dev_dbg(&dev->dev, "get resources\n"); + pnp_init_resources(dev); + isapnp_cfg_begin(dev->card->number, dev->number); dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); - if (dev->active) { - for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) { - ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); - if (!ret) - continue; - res->port_resource[tmp].start = ret; - res->port_resource[tmp].flags = IORESOURCE_IO; + if (!dev->active) + goto __end; + + for (i = 0; i < ISAPNP_MAX_PORT; i++) { + ret = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1)); + if (ret) { + pnp_res = pnp_add_io_resource(dev, ret, ret, 0); + if (pnp_res) + pnp_res->index = i; } - for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) { - ret = - isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8; - if (!ret) - continue; - res->mem_resource[tmp].start = ret; - res->mem_resource[tmp].flags = IORESOURCE_MEM; + } + for (i = 0; i < ISAPNP_MAX_MEM; i++) { + ret = isapnp_read_word(ISAPNP_CFG_MEM + (i << 3)) << 8; + if (ret) { + pnp_res = pnp_add_mem_resource(dev, ret, ret, 0); + if (pnp_res) + pnp_res->index = i; } - for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) { - ret = - (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> - 8); - if (!ret) - continue; - res->irq_resource[tmp].start = - res->irq_resource[tmp].end = ret; - res->irq_resource[tmp].flags = IORESOURCE_IRQ; + } + for (i = 0; i < ISAPNP_MAX_IRQ; i++) { + ret = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)) >> 8; + if (ret) { + pnp_res = pnp_add_irq_resource(dev, ret, 0); + if (pnp_res) + pnp_res->index = i; } - for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) { - ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); - if (ret == 4) - continue; - res->dma_resource[tmp].start = - res->dma_resource[tmp].end = ret; - res->dma_resource[tmp].flags = IORESOURCE_DMA; + } + for (i = 0; i < ISAPNP_MAX_DMA; i++) { + ret = isapnp_read_byte(ISAPNP_CFG_DMA + i); + if (ret != 4) { + pnp_res = pnp_add_dma_resource(dev, ret, 0); + if (pnp_res) + pnp_res->index = i; } } - return 0; -} - -static int isapnp_get_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) -{ - int ret; - pnp_init_resource_table(res); - isapnp_cfg_begin(dev->card->number, dev->number); - ret = isapnp_read_resources(dev, res); +__end: isapnp_cfg_end(); - return ret; + return 0; } -static int isapnp_set_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int isapnp_set_resources(struct pnp_dev *dev) { - int tmp; + struct pnp_resource *pnp_res; + struct resource *res; + int tmp, index; + dev_dbg(&dev->dev, "set resources\n"); isapnp_cfg_begin(dev->card->number, dev->number); dev->active = 1; - for (tmp = 0; - tmp < ISAPNP_MAX_PORT - && (res->port_resource[tmp]. - flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; - tmp++) - isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1), - res->port_resource[tmp].start); - for (tmp = 0; - tmp < ISAPNP_MAX_IRQ - && (res->irq_resource[tmp]. - flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; - tmp++) { - int irq = res->irq_resource[tmp].start; - if (irq == 2) - irq = 9; - isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq); + for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, tmp); + if (!pnp_res) + continue; + res = &pnp_res->res; + if (pnp_resource_valid(res)) { + index = pnp_res->index; + dev_dbg(&dev->dev, " set io %d to %#llx\n", + index, (unsigned long long) res->start); + isapnp_write_word(ISAPNP_CFG_PORT + (index << 1), + res->start); + } + } + for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, tmp); + if (!pnp_res) + continue; + res = &pnp_res->res; + if (pnp_resource_valid(res)) { + int irq = res->start; + if (irq == 2) + irq = 9; + index = pnp_res->index; + dev_dbg(&dev->dev, " set irq %d to %d\n", index, irq); + isapnp_write_byte(ISAPNP_CFG_IRQ + (index << 1), irq); + } + } + for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, tmp); + if (!pnp_res) + continue; + res = &pnp_res->res; + if (pnp_resource_valid(res)) { + index = pnp_res->index; + dev_dbg(&dev->dev, " set dma %d to %lld\n", + index, (unsigned long long) res->start); + isapnp_write_byte(ISAPNP_CFG_DMA + index, res->start); + } + } + for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, tmp); + if (!pnp_res) + continue; + res = &pnp_res->res; + if (pnp_resource_valid(res)) { + index = pnp_res->index; + dev_dbg(&dev->dev, " set mem %d to %#llx\n", + index, (unsigned long long) res->start); + isapnp_write_word(ISAPNP_CFG_MEM + (index << 3), + (res->start >> 8) & 0xffff); + } } - for (tmp = 0; - tmp < ISAPNP_MAX_DMA - && (res->dma_resource[tmp]. - flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; - tmp++) - isapnp_write_byte(ISAPNP_CFG_DMA + tmp, - res->dma_resource[tmp].start); - for (tmp = 0; - tmp < ISAPNP_MAX_MEM - && (res->mem_resource[tmp]. - flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; - tmp++) - isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3), - (res->mem_resource[tmp].start >> 8) & 0xffff); /* FIXME: We aren't handling 32bit mems properly here */ isapnp_activate(dev->number); isapnp_cfg_end(); @@ -1138,13 +1134,13 @@ static int __init isapnp_init(void) protocol_for_each_card(&isapnp_protocol, card) { cards++; if (isapnp_verbose) { - printk(KERN_INFO "isapnp: Card '%s'\n", - card->name[0] ? card->name : "Unknown"); + dev_info(&card->dev, "card '%s'\n", + card->name[0] ? card->name : "unknown"); if (isapnp_verbose < 2) continue; card_for_each_dev(card, dev) { - printk(KERN_INFO "isapnp: Device '%s'\n", - dev->name[0] ? dev->name : "Unknown"); + dev_info(&card->dev, "device '%s'\n", + dev->name[0] ? dev->name : "unknown"); } } } diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 2b8266c3d40f..3f94edab25fa 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -85,6 +85,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf, } static const struct file_operations isapnp_proc_bus_file_operations = { + .owner = THIS_MODULE, .llseek = isapnp_proc_bus_lseek, .read = isapnp_proc_bus_read, }; @@ -102,12 +103,10 @@ static int isapnp_proc_attach_device(struct pnp_dev *dev) return -ENOMEM; } sprintf(name, "%02x", dev->number); - e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); + e = dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, de, + &isapnp_proc_bus_file_operations, dev); if (!e) return -ENOMEM; - e->proc_fops = &isapnp_proc_bus_file_operations; - e->owner = THIS_MODULE; - e->data = dev; e->size = 256; return 0; } @@ -116,7 +115,7 @@ int __init isapnp_proc_init(void) { struct pnp_dev *dev; - isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); + isapnp_proc_bus_dir = proc_mkdir("bus/isapnp", NULL); protocol_for_each_dev(&isapnp_protocol, dev) { isapnp_proc_attach_device(dev); } diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index c28caf272c11..bea0914ff947 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -19,100 +19,118 @@ DEFINE_MUTEX(pnp_res_mutex); static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) { - resource_size_t *start, *end; - unsigned long *flags; + struct pnp_resource *pnp_res; + struct resource *res; - if (idx >= PNP_MAX_PORT) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, idx); + if (!pnp_res) { dev_err(&dev->dev, "too many I/O port resources\n"); /* pretend we were successful so at least the manager won't try again */ return 1; } + res = &pnp_res->res; + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) { + dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx " + "flags %#lx\n", idx, (unsigned long long) res->start, + (unsigned long long) res->end, res->flags); return 1; - - start = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; - flags = &dev->res.port_resource[idx].flags; + } /* set the initial values */ - *flags |= rule->flags | IORESOURCE_IO; - *flags &= ~IORESOURCE_UNSET; + pnp_res->index = idx; + res->flags |= rule->flags | IORESOURCE_IO; + res->flags &= ~IORESOURCE_UNSET; if (!rule->size) { - *flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED; + dev_dbg(&dev->dev, " io %d disabled\n", idx); return 1; /* skip disabled resource requests */ } - *start = rule->min; - *end = *start + rule->size - 1; + res->start = rule->min; + res->end = res->start + rule->size - 1; /* run through until pnp_check_port is happy */ - while (!pnp_check_port(dev, idx)) { - *start += rule->align; - *end = *start + rule->size - 1; - if (*start > rule->max || !rule->align) + while (!pnp_check_port(dev, res)) { + res->start += rule->align; + res->end = res->start + rule->size - 1; + if (res->start > rule->max || !rule->align) { + dev_dbg(&dev->dev, " couldn't assign io %d\n", idx); return 0; + } } + dev_dbg(&dev->dev, " assign io %d %#llx-%#llx\n", idx, + (unsigned long long) res->start, (unsigned long long) res->end); return 1; } static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) { - resource_size_t *start, *end; - unsigned long *flags; + struct pnp_resource *pnp_res; + struct resource *res; - if (idx >= PNP_MAX_MEM) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, idx); + if (!pnp_res) { dev_err(&dev->dev, "too many memory resources\n"); /* pretend we were successful so at least the manager won't try again */ return 1; } + res = &pnp_res->res; + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) { + dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " + "flags %#lx\n", idx, (unsigned long long) res->start, + (unsigned long long) res->end, res->flags); return 1; - - start = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; - flags = &dev->res.mem_resource[idx].flags; + } /* set the initial values */ - *flags |= rule->flags | IORESOURCE_MEM; - *flags &= ~IORESOURCE_UNSET; + pnp_res->index = idx; + res->flags |= rule->flags | IORESOURCE_MEM; + res->flags &= ~IORESOURCE_UNSET; /* convert pnp flags to standard Linux flags */ if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) - *flags |= IORESOURCE_READONLY; + res->flags |= IORESOURCE_READONLY; if (rule->flags & IORESOURCE_MEM_CACHEABLE) - *flags |= IORESOURCE_CACHEABLE; + res->flags |= IORESOURCE_CACHEABLE; if (rule->flags & IORESOURCE_MEM_RANGELENGTH) - *flags |= IORESOURCE_RANGELENGTH; + res->flags |= IORESOURCE_RANGELENGTH; if (rule->flags & IORESOURCE_MEM_SHADOWABLE) - *flags |= IORESOURCE_SHADOWABLE; + res->flags |= IORESOURCE_SHADOWABLE; if (!rule->size) { - *flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED; + dev_dbg(&dev->dev, " mem %d disabled\n", idx); return 1; /* skip disabled resource requests */ } - *start = rule->min; - *end = *start + rule->size - 1; + res->start = rule->min; + res->end = res->start + rule->size - 1; /* run through until pnp_check_mem is happy */ - while (!pnp_check_mem(dev, idx)) { - *start += rule->align; - *end = *start + rule->size - 1; - if (*start > rule->max || !rule->align) + while (!pnp_check_mem(dev, res)) { + res->start += rule->align; + res->end = res->start + rule->size - 1; + if (res->start > rule->max || !rule->align) { + dev_dbg(&dev->dev, " couldn't assign mem %d\n", idx); return 0; + } } + dev_dbg(&dev->dev, " assign mem %d %#llx-%#llx\n", idx, + (unsigned long long) res->start, (unsigned long long) res->end); return 1; } static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) { - resource_size_t *start, *end; - unsigned long *flags; + struct pnp_resource *pnp_res; + struct resource *res; int i; /* IRQ priority: this table is good for i386 */ @@ -120,49 +138,59 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 }; - if (idx >= PNP_MAX_IRQ) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, idx); + if (!pnp_res) { dev_err(&dev->dev, "too many IRQ resources\n"); /* pretend we were successful so at least the manager won't try again */ return 1; } + res = &pnp_res->res; + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) { + dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", + idx, (int) res->start, res->flags); return 1; - - start = &dev->res.irq_resource[idx].start; - end = &dev->res.irq_resource[idx].end; - flags = &dev->res.irq_resource[idx].flags; + } /* set the initial values */ - *flags |= rule->flags | IORESOURCE_IRQ; - *flags &= ~IORESOURCE_UNSET; + pnp_res->index = idx; + res->flags |= rule->flags | IORESOURCE_IRQ; + res->flags &= ~IORESOURCE_UNSET; if (bitmap_empty(rule->map, PNP_IRQ_NR)) { - *flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED; + dev_dbg(&dev->dev, " irq %d disabled\n", idx); return 1; /* skip disabled resource requests */ } /* TBD: need check for >16 IRQ */ - *start = find_next_bit(rule->map, PNP_IRQ_NR, 16); - if (*start < PNP_IRQ_NR) { - *end = *start; + res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16); + if (res->start < PNP_IRQ_NR) { + res->end = res->start; + dev_dbg(&dev->dev, " assign irq %d %d\n", idx, + (int) res->start); return 1; } for (i = 0; i < 16; i++) { if (test_bit(xtab[i], rule->map)) { - *start = *end = xtab[i]; - if (pnp_check_irq(dev, idx)) + res->start = res->end = xtab[i]; + if (pnp_check_irq(dev, res)) { + dev_dbg(&dev->dev, " assign irq %d %d\n", idx, + (int) res->start); return 1; + } } } + dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx); return 0; } static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { - resource_size_t *start, *end; - unsigned long *flags; + struct pnp_resource *pnp_res; + struct resource *res; int i; /* DMA priority: this table is good for i386 */ @@ -170,71 +198,89 @@ static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) 1, 3, 5, 6, 7, 0, 2, 4 }; - if (idx >= PNP_MAX_DMA) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, idx); + if (!pnp_res) { dev_err(&dev->dev, "too many DMA resources\n"); return; } + res = &pnp_res->res; + /* check if this resource has been manually set, if so skip */ - if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) + if (!(res->flags & IORESOURCE_AUTO)) { + dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", + idx, (int) res->start, res->flags); return; - - start = &dev->res.dma_resource[idx].start; - end = &dev->res.dma_resource[idx].end; - flags = &dev->res.dma_resource[idx].flags; + } /* set the initial values */ - *flags |= rule->flags | IORESOURCE_DMA; - *flags &= ~IORESOURCE_UNSET; + pnp_res->index = idx; + res->flags |= rule->flags | IORESOURCE_DMA; + res->flags &= ~IORESOURCE_UNSET; for (i = 0; i < 8; i++) { if (rule->map & (1 << xtab[i])) { - *start = *end = xtab[i]; - if (pnp_check_dma(dev, idx)) + res->start = res->end = xtab[i]; + if (pnp_check_dma(dev, res)) { + dev_dbg(&dev->dev, " assign dma %d %d\n", idx, + (int) res->start); return; + } } } #ifdef MAX_DMA_CHANNELS - *start = *end = MAX_DMA_CHANNELS; + res->start = res->end = MAX_DMA_CHANNELS; #endif - *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; + dev_dbg(&dev->dev, " disable dma %d\n", idx); +} + +void pnp_init_resource(struct resource *res) +{ + unsigned long type; + + type = res->flags & (IORESOURCE_IO | IORESOURCE_MEM | + IORESOURCE_IRQ | IORESOURCE_DMA); + + res->name = NULL; + res->flags = type | IORESOURCE_AUTO | IORESOURCE_UNSET; + if (type == IORESOURCE_IRQ || type == IORESOURCE_DMA) { + res->start = -1; + res->end = -1; + } else { + res->start = 0; + res->end = 0; + } } /** * pnp_init_resources - Resets a resource table to default values. * @table: pointer to the desired resource table */ -void pnp_init_resource_table(struct pnp_resource_table *table) +void pnp_init_resources(struct pnp_dev *dev) { + struct resource *res; int idx; for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - table->irq_resource[idx].name = NULL; - table->irq_resource[idx].start = -1; - table->irq_resource[idx].end = -1; - table->irq_resource[idx].flags = - IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->irq[idx].res; + res->flags = IORESOURCE_IRQ; + pnp_init_resource(res); } for (idx = 0; idx < PNP_MAX_DMA; idx++) { - table->dma_resource[idx].name = NULL; - table->dma_resource[idx].start = -1; - table->dma_resource[idx].end = -1; - table->dma_resource[idx].flags = - IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->dma[idx].res; + res->flags = IORESOURCE_DMA; + pnp_init_resource(res); } for (idx = 0; idx < PNP_MAX_PORT; idx++) { - table->port_resource[idx].name = NULL; - table->port_resource[idx].start = 0; - table->port_resource[idx].end = 0; - table->port_resource[idx].flags = - IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->port[idx].res; + res->flags = IORESOURCE_IO; + pnp_init_resource(res); } for (idx = 0; idx < PNP_MAX_MEM; idx++) { - table->mem_resource[idx].name = NULL; - table->mem_resource[idx].start = 0; - table->mem_resource[idx].end = 0; - table->mem_resource[idx].flags = - IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->mem[idx].res; + res->flags = IORESOURCE_MEM; + pnp_init_resource(res); } } @@ -242,41 +288,38 @@ void pnp_init_resource_table(struct pnp_resource_table *table) * pnp_clean_resources - clears resources that were not manually set * @res: the resources to clean */ -static void pnp_clean_resource_table(struct pnp_resource_table *res) +static void pnp_clean_resource_table(struct pnp_dev *dev) { + struct resource *res; int idx; for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO)) - continue; - res->irq_resource[idx].start = -1; - res->irq_resource[idx].end = -1; - res->irq_resource[idx].flags = - IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->irq[idx].res; + if (res->flags & IORESOURCE_AUTO) { + res->flags = IORESOURCE_IRQ; + pnp_init_resource(res); + } } for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO)) - continue; - res->dma_resource[idx].start = -1; - res->dma_resource[idx].end = -1; - res->dma_resource[idx].flags = - IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->dma[idx].res; + if (res->flags & IORESOURCE_AUTO) { + res->flags = IORESOURCE_DMA; + pnp_init_resource(res); + } } for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (!(res->port_resource[idx].flags & IORESOURCE_AUTO)) - continue; - res->port_resource[idx].start = 0; - res->port_resource[idx].end = 0; - res->port_resource[idx].flags = - IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->port[idx].res; + if (res->flags & IORESOURCE_AUTO) { + res->flags = IORESOURCE_IO; + pnp_init_resource(res); + } } for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO)) - continue; - res->mem_resource[idx].start = 0; - res->mem_resource[idx].end = 0; - res->mem_resource[idx].flags = - IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET; + res = &dev->res->mem[idx].res; + if (res->flags & IORESOURCE_AUTO) { + res->flags = IORESOURCE_MEM; + pnp_init_resource(res); + } } } @@ -298,9 +341,11 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) if (!pnp_can_configure(dev)) return -ENODEV; + dbg_pnp_show_resources(dev, "before pnp_assign_resources"); mutex_lock(&pnp_res_mutex); - pnp_clean_resource_table(&dev->res); /* start with a fresh slate */ + pnp_clean_resource_table(dev); if (dev->independent) { + dev_dbg(&dev->dev, "assigning independent options\n"); port = dev->independent->port; mem = dev->independent->mem; irq = dev->independent->irq; @@ -333,6 +378,8 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) if (depnum) { struct pnp_option *dep; int i; + + dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum); for (i = 1, dep = dev->dependent; i < depnum; i++, dep = dep->next) if (!dep) @@ -368,68 +415,17 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) goto fail; mutex_unlock(&pnp_res_mutex); + dbg_pnp_show_resources(dev, "after pnp_assign_resources"); return 1; fail: - pnp_clean_resource_table(&dev->res); + pnp_clean_resource_table(dev); mutex_unlock(&pnp_res_mutex); + dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)"); return 0; } /** - * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table - * @dev: pointer to the desired device - * @res: pointer to the new resource config - * @mode: 0 or PNP_CONFIG_FORCE - * - * This function can be used by drivers that want to manually set thier resources. - */ -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, - int mode) -{ - int i; - struct pnp_resource_table *bak; - - if (!pnp_can_configure(dev)) - return -ENODEV; - bak = pnp_alloc(sizeof(struct pnp_resource_table)); - if (!bak) - return -ENOMEM; - *bak = dev->res; - - mutex_lock(&pnp_res_mutex); - dev->res = *res; - if (!(mode & PNP_CONFIG_FORCE)) { - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_check_port(dev, i)) - goto fail; - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_check_mem(dev, i)) - goto fail; - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (!pnp_check_irq(dev, i)) - goto fail; - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (!pnp_check_dma(dev, i)) - goto fail; - } - } - mutex_unlock(&pnp_res_mutex); - - kfree(bak); - return 0; - -fail: - dev->res = *bak; - mutex_unlock(&pnp_res_mutex); - kfree(bak); - return -EINVAL; -} - -/** * pnp_auto_config_dev - automatically assigns resources to a device * @dev: pointer to the desired device */ @@ -473,7 +469,8 @@ int pnp_start_dev(struct pnp_dev *dev) return -EINVAL; } - if (dev->protocol->set(dev, &dev->res) < 0) { + dbg_pnp_show_resources(dev, "pnp_start_dev"); + if (dev->protocol->set(dev) < 0) { dev_err(&dev->dev, "activation failed\n"); return -EIO; } @@ -549,30 +546,13 @@ int pnp_disable_dev(struct pnp_dev *dev) /* release the resources so that other devices can use them */ mutex_lock(&pnp_res_mutex); - pnp_clean_resource_table(&dev->res); + pnp_clean_resource_table(dev); mutex_unlock(&pnp_res_mutex); return 0; } -/** - * pnp_resource_change - change one resource - * @resource: pointer to resource to be changed - * @start: start of region - * @size: size of region - */ -void pnp_resource_change(struct resource *resource, resource_size_t start, - resource_size_t size) -{ - resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET); - resource->start = start; - resource->end = start + size - 1; -} - -EXPORT_SYMBOL(pnp_manual_config_dev); EXPORT_SYMBOL(pnp_start_dev); EXPORT_SYMBOL(pnp_stop_dev); EXPORT_SYMBOL(pnp_activate_dev); EXPORT_SYMBOL(pnp_disable_dev); -EXPORT_SYMBOL(pnp_resource_change); -EXPORT_SYMBOL(pnp_init_resource_table); diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile index 905326fcca85..2d7a1e6908be 100644 --- a/drivers/pnp/pnpacpi/Makefile +++ b/drivers/pnp/pnpacpi/Makefile @@ -3,3 +3,7 @@ # obj-y := core.o rsparser.o + +ifeq ($(CONFIG_PNP_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index c283a9a70d83..50902773beaf 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -25,6 +25,7 @@ #include <acpi/acpi_bus.h> #include <acpi/actypes.h> +#include "../base.h" #include "pnpacpi.h" static int num = 0; @@ -44,7 +45,7 @@ static struct acpi_device_id excluded_id_list[] __initdata = { {"", 0}, }; -static inline int is_exclusive_device(struct acpi_device *dev) +static inline int __init is_exclusive_device(struct acpi_device *dev) { return (!acpi_match_device_ids(dev, excluded_id_list)); } @@ -72,40 +73,24 @@ static int __init ispnpidacpi(char *id) return 1; } -static void __init pnpidacpi_to_pnpid(char *id, char *str) +static int pnpacpi_get_resources(struct pnp_dev *dev) { - str[0] = id[0]; - str[1] = id[1]; - str[2] = id[2]; - str[3] = tolower(id[3]); - str[4] = tolower(id[4]); - str[5] = tolower(id[5]); - str[6] = tolower(id[6]); - str[7] = '\0'; + dev_dbg(&dev->dev, "get resources\n"); + return pnpacpi_parse_allocated_resource(dev); } -static int pnpacpi_get_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) -{ - acpi_status status; - - status = pnpacpi_parse_allocated_resource((acpi_handle) dev->data, - &dev->res); - return ACPI_FAILURE(status) ? -ENODEV : 0; -} - -static int pnpacpi_set_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpacpi_set_resources(struct pnp_dev *dev) { acpi_handle handle = dev->data; struct acpi_buffer buffer; - int ret = 0; + int ret; acpi_status status; - ret = pnpacpi_build_resource_template(handle, &buffer); + dev_dbg(&dev->dev, "set resources\n"); + ret = pnpacpi_build_resource_template(dev, &buffer); if (ret) return ret; - ret = pnpacpi_encode_resources(res, &buffer); + ret = pnpacpi_encode_resources(dev, &buffer); if (ret) { kfree(buffer.pointer); return ret; @@ -163,7 +148,6 @@ static int __init pnpacpi_add_device(struct acpi_device *device) { acpi_handle temp = NULL; acpi_status status; - struct pnp_id *dev_id; struct pnp_dev *dev; status = acpi_get_handle(device->handle, "_CRS", &temp); @@ -171,11 +155,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device) is_exclusive_device(device)) return 0; - dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); - if (!dev) { - pnp_err("Out of memory"); + dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device)); + if (!dev) return -ENOMEM; - } + dev->data = device->handle; /* .enabled means the device can decode the resources */ dev->active = device->status.enabled; @@ -191,44 +174,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (ACPI_SUCCESS(status)) dev->capabilities |= PNP_DISABLE; - dev->protocol = &pnpacpi_protocol; - if (strlen(acpi_device_name(device))) strncpy(dev->name, acpi_device_name(device), sizeof(dev->name)); else strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); - dev->number = num; - - /* set the initial values for the PnP device */ - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) - goto err; - pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id); - pnp_add_id(dev_id, dev); - - if (dev->active) { - /* parse allocated resource */ - status = pnpacpi_parse_allocated_resource(device->handle, - &dev->res); - if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { - pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", - dev_id->id); - goto err1; - } - } + if (dev->active) + pnpacpi_parse_allocated_resource(dev); - if (dev->capabilities & PNP_CONFIGURABLE) { - status = pnpacpi_parse_resource_option_data(device->handle, - dev); - if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { - pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", - dev_id->id); - goto err1; - } - } + if (dev->capabilities & PNP_CONFIGURABLE) + pnpacpi_parse_resource_option_data(dev); - /* parse compatible ids */ if (device->flags.compatible_ids) { struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; int i; @@ -236,27 +192,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device) for (i = 0; i < cid_list->count; i++) { if (!ispnpidacpi(cid_list->id[i].value)) continue; - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) - continue; - - pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id); - pnp_add_id(dev_id, dev); + pnp_add_id(dev, cid_list->id[i].value); } } /* clear out the damaged flags */ if (!dev->active) - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); pnp_add_device(dev); num++; return AE_OK; -err1: - kfree(dev_id); -err: - kfree(dev); - return -EINVAL; } static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h index f28e2ed66fa3..3e60225b0227 100644 --- a/drivers/pnp/pnpacpi/pnpacpi.h +++ b/drivers/pnp/pnpacpi/pnpacpi.h @@ -5,8 +5,8 @@ #include <linux/acpi.h> #include <linux/pnp.h> -acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*); -acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*); -int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *); -int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*); +int pnpacpi_parse_allocated_resource(struct pnp_dev *); +int pnpacpi_parse_resource_option_data(struct pnp_dev *); +int pnpacpi_encode_resources(struct pnp_dev *, struct acpi_buffer *); +int pnpacpi_build_resource_template(struct pnp_dev *, struct acpi_buffer *); #endif diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 98cbc9f18eed..0201c8adfda7 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -21,6 +21,8 @@ #include <linux/kernel.h> #include <linux/acpi.h> #include <linux/pci.h> +#include <linux/pnp.h> +#include "../base.h" #include "pnpacpi.h" #ifdef CONFIG_IA64 @@ -32,19 +34,26 @@ /* * Allocated Resources */ -static int irq_flags(int triggering, int polarity) +static int irq_flags(int triggering, int polarity, int shareable) { + int flags; + if (triggering == ACPI_LEVEL_SENSITIVE) { if (polarity == ACPI_ACTIVE_LOW) - return IORESOURCE_IRQ_LOWLEVEL; + flags = IORESOURCE_IRQ_LOWLEVEL; else - return IORESOURCE_IRQ_HIGHLEVEL; + flags = IORESOURCE_IRQ_HIGHLEVEL; } else { if (polarity == ACPI_ACTIVE_LOW) - return IORESOURCE_IRQ_LOWEDGE; + flags = IORESOURCE_IRQ_LOWEDGE; else - return IORESOURCE_IRQ_HIGHEDGE; + flags = IORESOURCE_IRQ_HIGHEDGE; } + + if (shareable) + flags |= IORESOURCE_IRQ_SHAREABLE; + + return flags; } static void decode_irq_flags(int flag, int *triggering, int *polarity) @@ -69,29 +78,16 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity) } } -static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, +static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, u32 gsi, int triggering, int polarity, int shareable) { - int i = 0; - int irq; + int irq, flags; int p, t; - static unsigned char warned; if (!valid_IRQ(gsi)) return; - while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && - i < PNP_MAX_IRQ) - i++; - if (i >= PNP_MAX_IRQ) { - if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number" - " of IRQ resources: %d\n", PNP_MAX_IRQ); - warned = 1; - } - return; - } /* * in IO-APIC mode, use overrided attribute. Two reasons: * 1. BIOS bug in DSDT @@ -102,27 +98,21 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; if (triggering != t || polarity != p) { - pnp_warn("IRQ %d override to %s, %s", + dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", gsi, t ? "edge":"level", p ? "low":"high"); triggering = t; polarity = p; } } - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag - res->irq_resource[i].flags |= irq_flags(triggering, polarity); + flags = irq_flags(triggering, polarity, shareable); irq = acpi_register_gsi(gsi, triggering, polarity); - if (irq < 0) { - res->irq_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - - if (shareable) - res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE; + if (irq >= 0) + pcibios_penalize_isa_irq(irq, 1); + else + flags |= IORESOURCE_DISABLED; - res->irq_resource[i].start = irq; - res->irq_resource[i].end = irq; - pcibios_penalize_isa_irq(irq, 1); + pnp_add_irq_resource(dev, irq, flags); } static int dma_flags(int type, int bus_master, int transfer) @@ -168,88 +158,36 @@ static int dma_flags(int type, int bus_master, int transfer) return flags; } -static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, - u32 dma, int type, - int bus_master, int transfer) +static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, + u64 len, int io_decode) { - int i = 0; - static unsigned char warned; - - while (i < PNP_MAX_DMA && - !(res->dma_resource[i].flags & IORESOURCE_UNSET)) - i++; - if (i < PNP_MAX_DMA) { - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag - res->dma_resource[i].flags |= - dma_flags(type, bus_master, transfer); - if (dma == -1) { - res->dma_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->dma_resource[i].start = dma; - res->dma_resource[i].end = dma; - } else if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of DMA " - "resources: %d \n", PNP_MAX_DMA); - warned = 1; - } -} + int flags = 0; + u64 end = start + len - 1; -static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res, - u64 io, u64 len, int io_decode) -{ - int i = 0; - static unsigned char warned; + if (io_decode == ACPI_DECODE_16) + flags |= PNP_PORT_FLAG_16BITADDR; + if (len == 0 || end >= 0x10003) + flags |= IORESOURCE_DISABLED; - while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && - i < PNP_MAX_PORT) - i++; - if (i < PNP_MAX_PORT) { - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag - if (io_decode == ACPI_DECODE_16) - res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR; - if (len <= 0 || (io + len - 1) >= 0x10003) { - res->port_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->port_resource[i].start = io; - res->port_resource[i].end = io + len - 1; - } else if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of IO " - "resources: %d \n", PNP_MAX_PORT); - warned = 1; - } + pnp_add_io_resource(dev, start, end, flags); } -static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res, - u64 mem, u64 len, +static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, + u64 start, u64 len, int write_protect) { - int i = 0; - static unsigned char warned; + int flags = 0; + u64 end = start + len - 1; - while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && - (i < PNP_MAX_MEM)) - i++; - if (i < PNP_MAX_MEM) { - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag - if (len <= 0) { - res->mem_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - if (write_protect == ACPI_READ_WRITE_MEMORY) - res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE; - - res->mem_resource[i].start = mem; - res->mem_resource[i].end = mem + len - 1; - } else if (!warned) { - printk(KERN_WARNING "pnpacpi: exceeded the max number of mem " - "resources: %d\n", PNP_MAX_MEM); - warned = 1; - } + if (len == 0) + flags |= IORESOURCE_DISABLED; + if (write_protect == ACPI_READ_WRITE_MEMORY) + flags |= IORESOURCE_MEM_WRITEABLE; + + pnp_add_mem_resource(dev, start, end, flags); } -static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table, +static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, struct acpi_resource *res) { struct acpi_resource_address64 addr, *p = &addr; @@ -257,7 +195,7 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res status = acpi_resource_to_address64(res, p); if (!ACPI_SUCCESS(status)) { - pnp_warn("PnPACPI: failed to convert resource type %d", + dev_warn(&dev->dev, "failed to convert resource type %d\n", res->type); return; } @@ -266,11 +204,11 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res return; if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(res_table, + pnpacpi_parse_allocated_memresource(dev, p->minimum, p->address_length, p->info.mem.write_protect); else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(res_table, + pnpacpi_parse_allocated_ioresource(dev, p->minimum, p->address_length, p->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16); @@ -279,8 +217,16 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, void *data) { - struct pnp_resource_table *res_table = data; - int i; + struct pnp_dev *dev = data; + struct acpi_resource_irq *irq; + struct acpi_resource_dma *dma; + struct acpi_resource_io *io; + struct acpi_resource_fixed_io *fixed_io; + struct acpi_resource_memory24 *memory24; + struct acpi_resource_memory32 *memory32; + struct acpi_resource_fixed_memory32 *fixed_memory32; + struct acpi_resource_extended_irq *extended_irq; + int i, flags; switch (res->type) { case ACPI_RESOURCE_TYPE_IRQ: @@ -288,29 +234,33 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, * Per spec, only one interrupt per descriptor is allowed in * _CRS, but some firmware violates this, so parse them all. */ - for (i = 0; i < res->data.irq.interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(res_table, - res->data.irq.interrupts[i], - res->data.irq.triggering, - res->data.irq.polarity, - res->data.irq.sharable); + irq = &res->data.irq; + for (i = 0; i < irq->interrupt_count; i++) { + pnpacpi_parse_allocated_irqresource(dev, + irq->interrupts[i], + irq->triggering, + irq->polarity, + irq->sharable); } break; case ACPI_RESOURCE_TYPE_DMA: - if (res->data.dma.channel_count > 0) - pnpacpi_parse_allocated_dmaresource(res_table, - res->data.dma.channels[0], - res->data.dma.type, - res->data.dma.bus_master, - res->data.dma.transfer); + dma = &res->data.dma; + if (dma->channel_count > 0) { + flags = dma_flags(dma->type, dma->bus_master, + dma->transfer); + if (dma->channels[0] == (u8) -1) + flags |= IORESOURCE_DISABLED; + pnp_add_dma_resource(dev, dma->channels[0], flags); + } break; case ACPI_RESOURCE_TYPE_IO: - pnpacpi_parse_allocated_ioresource(res_table, - res->data.io.minimum, - res->data.io.address_length, - res->data.io.io_decode); + io = &res->data.io; + pnpacpi_parse_allocated_ioresource(dev, + io->minimum, + io->address_length, + io->io_decode); break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -318,9 +268,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_FIXED_IO: - pnpacpi_parse_allocated_ioresource(res_table, - res->data.fixed_io.address, - res->data.fixed_io.address_length, + fixed_io = &res->data.fixed_io; + pnpacpi_parse_allocated_ioresource(dev, + fixed_io->address, + fixed_io->address_length, ACPI_DECODE_10); break; @@ -331,27 +282,30 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_MEMORY24: - pnpacpi_parse_allocated_memresource(res_table, - res->data.memory24.minimum, - res->data.memory24.address_length, - res->data.memory24.write_protect); + memory24 = &res->data.memory24; + pnpacpi_parse_allocated_memresource(dev, + memory24->minimum, + memory24->address_length, + memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: - pnpacpi_parse_allocated_memresource(res_table, - res->data.memory32.minimum, - res->data.memory32.address_length, - res->data.memory32.write_protect); + memory32 = &res->data.memory32; + pnpacpi_parse_allocated_memresource(dev, + memory32->minimum, + memory32->address_length, + memory32->write_protect); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - pnpacpi_parse_allocated_memresource(res_table, - res->data.fixed_memory32.address, - res->data.fixed_memory32.address_length, - res->data.fixed_memory32.write_protect); + fixed_memory32 = &res->data.fixed_memory32; + pnpacpi_parse_allocated_memresource(dev, + fixed_memory32->address, + fixed_memory32->address_length, + fixed_memory32->write_protect); break; case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_allocated_address_space(res_table, res); + pnpacpi_parse_allocated_address_space(dev, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: @@ -360,15 +314,16 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER) + extended_irq = &res->data.extended_irq; + if (extended_irq->producer_consumer == ACPI_PRODUCER) return AE_OK; - for (i = 0; i < res->data.extended_irq.interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(res_table, - res->data.extended_irq.interrupts[i], - res->data.extended_irq.triggering, - res->data.extended_irq.polarity, - res->data.extended_irq.sharable); + for (i = 0; i < extended_irq->interrupt_count; i++) { + pnpacpi_parse_allocated_irqresource(dev, + extended_irq->interrupts[i], + extended_irq->triggering, + extended_irq->polarity, + extended_irq->sharable); } break; @@ -376,24 +331,36 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; default: - pnp_warn("PnPACPI: unknown resource type %d", res->type); + dev_warn(&dev->dev, "unknown resource type %d in _CRS\n", + res->type); return AE_ERROR; } return AE_OK; } -acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, - struct pnp_resource_table * res) +int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) { - /* Blank the resource table values */ - pnp_init_resource_table(res); + acpi_handle handle = dev->data; + acpi_status status; + + dev_dbg(&dev->dev, "parse allocated resources\n"); - return acpi_walk_resources(handle, METHOD_NAME__CRS, - pnpacpi_allocated_resource, res); + pnp_init_resources(dev); + + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + pnpacpi_allocated_resource, dev); + + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + dev_err(&dev->dev, "can't evaluate _CRS: %d", status); + return -EPERM; + } + return 0; } -static __init void pnpacpi_parse_dma_option(struct pnp_option *option, +static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_dma *p) { int i; @@ -410,10 +377,11 @@ static __init void pnpacpi_parse_dma_option(struct pnp_option *option, dma->flags = dma_flags(p->type, p->bus_master, p->transfer); - pnp_register_dma_resource(option, dma); + pnp_register_dma_resource(dev, option, dma); } -static __init void pnpacpi_parse_irq_option(struct pnp_option *option, +static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_irq *p) { int i; @@ -428,12 +396,13 @@ static __init void pnpacpi_parse_irq_option(struct pnp_option *option, for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], irq->map); - irq->flags = irq_flags(p->triggering, p->polarity); + irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); - pnp_register_irq_resource(option, irq); + pnp_register_irq_resource(dev, option, irq); } -static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option, +static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_extended_irq *p) { int i; @@ -448,12 +417,13 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option, for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], irq->map); - irq->flags = irq_flags(p->triggering, p->polarity); + irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); - pnp_register_irq_resource(option, irq); + pnp_register_irq_resource(dev, option, irq); } -static __init void pnpacpi_parse_port_option(struct pnp_option *option, +static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_io *io) { struct pnp_port *port; @@ -469,10 +439,11 @@ static __init void pnpacpi_parse_port_option(struct pnp_option *option, port->size = io->address_length; port->flags = ACPI_DECODE_16 == io->io_decode ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } -static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option, +static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_fixed_io *io) { struct pnp_port *port; @@ -486,10 +457,11 @@ static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option, port->size = io->address_length; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } -static __init void pnpacpi_parse_mem24_option(struct pnp_option *option, +static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_memory24 *p) { struct pnp_mem *mem; @@ -507,10 +479,11 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_option *option, mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? IORESOURCE_MEM_WRITEABLE : 0; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } -static __init void pnpacpi_parse_mem32_option(struct pnp_option *option, +static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_memory32 *p) { struct pnp_mem *mem; @@ -528,10 +501,11 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_option *option, mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? IORESOURCE_MEM_WRITEABLE : 0; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } -static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, +static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource_fixed_memory32 *p) { struct pnp_mem *mem; @@ -548,10 +522,11 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? IORESOURCE_MEM_WRITEABLE : 0; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } -static __init void pnpacpi_parse_address_option(struct pnp_option *option, +static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, + struct pnp_option *option, struct acpi_resource *r) { struct acpi_resource_address64 addr, *p = &addr; @@ -579,7 +554,7 @@ static __init void pnpacpi_parse_address_option(struct pnp_option *option, mem->flags = (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE : 0; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } else if (p->resource_type == ACPI_IO_RANGE) { port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); if (!port) @@ -588,7 +563,7 @@ static __init void pnpacpi_parse_address_option(struct pnp_option *option, port->size = p->address_length; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } } @@ -608,11 +583,11 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, switch (res->type) { case ACPI_RESOURCE_TYPE_IRQ: - pnpacpi_parse_irq_option(option, &res->data.irq); + pnpacpi_parse_irq_option(dev, option, &res->data.irq); break; case ACPI_RESOURCE_TYPE_DMA: - pnpacpi_parse_dma_option(option, &res->data.dma); + pnpacpi_parse_dma_option(dev, option, &res->data.dma); break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -642,19 +617,22 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_END_DEPENDENT: /*only one EndDependentFn is allowed */ if (!parse_data->option_independent) { - pnp_warn("PnPACPI: more than one EndDependentFn"); + dev_warn(&dev->dev, "more than one EndDependentFn " + "in _PRS\n"); return AE_ERROR; } parse_data->option = parse_data->option_independent; parse_data->option_independent = NULL; + dev_dbg(&dev->dev, "end dependent options\n"); break; case ACPI_RESOURCE_TYPE_IO: - pnpacpi_parse_port_option(option, &res->data.io); + pnpacpi_parse_port_option(dev, option, &res->data.io); break; case ACPI_RESOURCE_TYPE_FIXED_IO: - pnpacpi_parse_fixed_port_option(option, &res->data.fixed_io); + pnpacpi_parse_fixed_port_option(dev, option, + &res->data.fixed_io); break; case ACPI_RESOURCE_TYPE_VENDOR: @@ -662,57 +640,67 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_MEMORY24: - pnpacpi_parse_mem24_option(option, &res->data.memory24); + pnpacpi_parse_mem24_option(dev, option, &res->data.memory24); break; case ACPI_RESOURCE_TYPE_MEMORY32: - pnpacpi_parse_mem32_option(option, &res->data.memory32); + pnpacpi_parse_mem32_option(dev, option, &res->data.memory32); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - pnpacpi_parse_fixed_mem32_option(option, + pnpacpi_parse_fixed_mem32_option(dev, option, &res->data.fixed_memory32); break; case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_address_option(option, res); + pnpacpi_parse_address_option(dev, option, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - pnpacpi_parse_ext_irq_option(option, &res->data.extended_irq); + pnpacpi_parse_ext_irq_option(dev, option, + &res->data.extended_irq); break; case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: break; default: - pnp_warn("PnPACPI: unknown resource type %d", res->type); + dev_warn(&dev->dev, "unknown resource type %d in _PRS\n", + res->type); return AE_ERROR; } return AE_OK; } -acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle, - struct pnp_dev *dev) +int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) { + acpi_handle handle = dev->data; acpi_status status; struct acpipnp_parse_option_s parse_data; + dev_dbg(&dev->dev, "parse resource options\n"); + parse_data.option = pnp_register_independent_option(dev); if (!parse_data.option) - return AE_ERROR; + return -ENOMEM; + parse_data.option_independent = parse_data.option; parse_data.dev = dev; status = acpi_walk_resources(handle, METHOD_NAME__PRS, pnpacpi_option_resource, &parse_data); - return status; + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + dev_err(&dev->dev, "can't evaluate _PRS: %d", status); + return -EPERM; + } + return 0; } static int pnpacpi_supported_resource(struct acpi_resource *res) @@ -760,9 +748,10 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) return AE_OK; } -int pnpacpi_build_resource_template(acpi_handle handle, +int pnpacpi_build_resource_template(struct pnp_dev *dev, struct acpi_buffer *buffer) { + acpi_handle handle = dev->data; struct acpi_resource *resource; int res_cnt = 0; acpi_status status; @@ -770,7 +759,7 @@ int pnpacpi_build_resource_template(acpi_handle handle, status = acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_count_resources, &res_cnt); if (ACPI_FAILURE(status)) { - pnp_err("Evaluate _CRS failed"); + dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); return -EINVAL; } if (!res_cnt) @@ -779,13 +768,13 @@ int pnpacpi_build_resource_template(acpi_handle handle, buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); if (!buffer->pointer) return -ENOMEM; - pnp_dbg("Res cnt %d", res_cnt); + resource = (struct acpi_resource *)buffer->pointer; status = acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_type_resources, &resource); if (ACPI_FAILURE(status)) { kfree(buffer->pointer); - pnp_err("Evaluate _CRS failed"); + dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); return -EINVAL; } /* resource will pointer the end resource now */ @@ -794,129 +783,184 @@ int pnpacpi_build_resource_template(acpi_handle handle, return 0; } -static void pnpacpi_encode_irq(struct acpi_resource *resource, +static void pnpacpi_encode_irq(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_irq *irq = &resource->data.irq; int triggering, polarity; decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity); - resource->data.irq.triggering = triggering; - resource->data.irq.polarity = polarity; + irq->triggering = triggering; + irq->polarity = polarity; if (triggering == ACPI_EDGE_SENSITIVE) - resource->data.irq.sharable = ACPI_EXCLUSIVE; + irq->sharable = ACPI_EXCLUSIVE; else - resource->data.irq.sharable = ACPI_SHARED; - resource->data.irq.interrupt_count = 1; - resource->data.irq.interrupts[0] = p->start; + irq->sharable = ACPI_SHARED; + irq->interrupt_count = 1; + irq->interrupts[0] = p->start; + + dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, + triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", + polarity == ACPI_ACTIVE_LOW ? "low" : "high", + irq->sharable == ACPI_SHARED ? "shared" : "exclusive"); } -static void pnpacpi_encode_ext_irq(struct acpi_resource *resource, +static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; int triggering, polarity; decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity); - resource->data.extended_irq.producer_consumer = ACPI_CONSUMER; - resource->data.extended_irq.triggering = triggering; - resource->data.extended_irq.polarity = polarity; + extended_irq->producer_consumer = ACPI_CONSUMER; + extended_irq->triggering = triggering; + extended_irq->polarity = polarity; if (triggering == ACPI_EDGE_SENSITIVE) - resource->data.irq.sharable = ACPI_EXCLUSIVE; + extended_irq->sharable = ACPI_EXCLUSIVE; else - resource->data.irq.sharable = ACPI_SHARED; - resource->data.extended_irq.interrupt_count = 1; - resource->data.extended_irq.interrupts[0] = p->start; + extended_irq->sharable = ACPI_SHARED; + extended_irq->interrupt_count = 1; + extended_irq->interrupts[0] = p->start; + + dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, + triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", + polarity == ACPI_ACTIVE_LOW ? "low" : "high", + extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive"); } -static void pnpacpi_encode_dma(struct acpi_resource *resource, +static void pnpacpi_encode_dma(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_dma *dma = &resource->data.dma; + /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { case IORESOURCE_DMA_TYPEA: - resource->data.dma.type = ACPI_TYPE_A; + dma->type = ACPI_TYPE_A; break; case IORESOURCE_DMA_TYPEB: - resource->data.dma.type = ACPI_TYPE_B; + dma->type = ACPI_TYPE_B; break; case IORESOURCE_DMA_TYPEF: - resource->data.dma.type = ACPI_TYPE_F; + dma->type = ACPI_TYPE_F; break; default: - resource->data.dma.type = ACPI_COMPATIBILITY; + dma->type = ACPI_COMPATIBILITY; } switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { case IORESOURCE_DMA_8BIT: - resource->data.dma.transfer = ACPI_TRANSFER_8; + dma->transfer = ACPI_TRANSFER_8; break; case IORESOURCE_DMA_8AND16BIT: - resource->data.dma.transfer = ACPI_TRANSFER_8_16; + dma->transfer = ACPI_TRANSFER_8_16; break; default: - resource->data.dma.transfer = ACPI_TRANSFER_16; + dma->transfer = ACPI_TRANSFER_16; } - resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); - resource->data.dma.channel_count = 1; - resource->data.dma.channels[0] = p->start; + dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); + dma->channel_count = 1; + dma->channels[0] = p->start; + + dev_dbg(&dev->dev, " encode dma %d " + "type %#x transfer %#x master %d\n", + (int) p->start, dma->type, dma->transfer, dma->bus_master); } -static void pnpacpi_encode_io(struct acpi_resource *resource, +static void pnpacpi_encode_io(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_io *io = &resource->data.io; + /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */ - resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ? + io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ? ACPI_DECODE_16 : ACPI_DECODE_10; - resource->data.io.minimum = p->start; - resource->data.io.maximum = p->end; - resource->data.io.alignment = 0; /* Correct? */ - resource->data.io.address_length = p->end - p->start + 1; + io->minimum = p->start; + io->maximum = p->end; + io->alignment = 0; /* Correct? */ + io->address_length = p->end - p->start + 1; + + dev_dbg(&dev->dev, " encode io %#llx-%#llx decode %#x\n", + (unsigned long long) p->start, (unsigned long long) p->end, + io->io_decode); } -static void pnpacpi_encode_fixed_io(struct acpi_resource *resource, +static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { - resource->data.fixed_io.address = p->start; - resource->data.fixed_io.address_length = p->end - p->start + 1; + struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; + + fixed_io->address = p->start; + fixed_io->address_length = p->end - p->start + 1; + + dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n", + (unsigned long long) p->start, (unsigned long long) p->end); } -static void pnpacpi_encode_mem24(struct acpi_resource *resource, +static void pnpacpi_encode_mem24(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { + struct acpi_resource_memory24 *memory24 = &resource->data.memory24; + /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */ - resource->data.memory24.write_protect = + memory24->write_protect = (p->flags & IORESOURCE_MEM_WRITEABLE) ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; - resource->data.memory24.minimum = p->start; - resource->data.memory24.maximum = p->end; - resource->data.memory24.alignment = 0; - resource->data.memory24.address_length = p->end - p->start + 1; + memory24->minimum = p->start; + memory24->maximum = p->end; + memory24->alignment = 0; + memory24->address_length = p->end - p->start + 1; + + dev_dbg(&dev->dev, " encode mem24 %#llx-%#llx write_protect %#x\n", + (unsigned long long) p->start, (unsigned long long) p->end, + memory24->write_protect); } -static void pnpacpi_encode_mem32(struct acpi_resource *resource, +static void pnpacpi_encode_mem32(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { - resource->data.memory32.write_protect = + struct acpi_resource_memory32 *memory32 = &resource->data.memory32; + + memory32->write_protect = (p->flags & IORESOURCE_MEM_WRITEABLE) ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; - resource->data.memory32.minimum = p->start; - resource->data.memory32.maximum = p->end; - resource->data.memory32.alignment = 0; - resource->data.memory32.address_length = p->end - p->start + 1; + memory32->minimum = p->start; + memory32->maximum = p->end; + memory32->alignment = 0; + memory32->address_length = p->end - p->start + 1; + + dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx write_protect %#x\n", + (unsigned long long) p->start, (unsigned long long) p->end, + memory32->write_protect); } -static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource, +static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, + struct acpi_resource *resource, struct resource *p) { - resource->data.fixed_memory32.write_protect = + struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; + + fixed_memory32->write_protect = (p->flags & IORESOURCE_MEM_WRITEABLE) ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; - resource->data.fixed_memory32.address = p->start; - resource->data.fixed_memory32.address_length = p->end - p->start + 1; + fixed_memory32->address = p->start; + fixed_memory32->address_length = p->end - p->start + 1; + + dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx " + "write_protect %#x\n", + (unsigned long long) p->start, (unsigned long long) p->end, + fixed_memory32->write_protect); } -int pnpacpi_encode_resources(struct pnp_resource_table *res_table, - struct acpi_buffer *buffer) +int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) { int i = 0; /* pnpacpi_build_resource_template allocates extra mem */ @@ -924,58 +968,48 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table, struct acpi_resource *resource = buffer->pointer; int port = 0, irq = 0, dma = 0, mem = 0; - pnp_dbg("res cnt %d", res_cnt); + dev_dbg(&dev->dev, "encode %d resources\n", res_cnt); while (i < res_cnt) { switch (resource->type) { case ACPI_RESOURCE_TYPE_IRQ: - pnp_dbg("Encode irq"); - pnpacpi_encode_irq(resource, - &res_table->irq_resource[irq]); + pnpacpi_encode_irq(dev, resource, + pnp_get_resource(dev, IORESOURCE_IRQ, irq)); irq++; break; case ACPI_RESOURCE_TYPE_DMA: - pnp_dbg("Encode dma"); - pnpacpi_encode_dma(resource, - &res_table->dma_resource[dma]); + pnpacpi_encode_dma(dev, resource, + pnp_get_resource(dev, IORESOURCE_DMA, dma)); dma++; break; case ACPI_RESOURCE_TYPE_IO: - pnp_dbg("Encode io"); - pnpacpi_encode_io(resource, - &res_table->port_resource[port]); + pnpacpi_encode_io(dev, resource, + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; case ACPI_RESOURCE_TYPE_FIXED_IO: - pnp_dbg("Encode fixed io"); - pnpacpi_encode_fixed_io(resource, - &res_table-> - port_resource[port]); + pnpacpi_encode_fixed_io(dev, resource, + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; case ACPI_RESOURCE_TYPE_MEMORY24: - pnp_dbg("Encode mem24"); - pnpacpi_encode_mem24(resource, - &res_table->mem_resource[mem]); + pnpacpi_encode_mem24(dev, resource, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case ACPI_RESOURCE_TYPE_MEMORY32: - pnp_dbg("Encode mem32"); - pnpacpi_encode_mem32(resource, - &res_table->mem_resource[mem]); + pnpacpi_encode_mem32(dev, resource, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - pnp_dbg("Encode fixed mem32"); - pnpacpi_encode_fixed_mem32(resource, - &res_table-> - mem_resource[mem]); + pnpacpi_encode_fixed_mem32(dev, resource, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - pnp_dbg("Encode ext irq"); - pnpacpi_encode_ext_irq(resource, - &res_table->irq_resource[irq]); + pnpacpi_encode_ext_irq(dev, resource, + pnp_get_resource(dev, IORESOURCE_IRQ, irq)); irq++; break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -988,7 +1022,8 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table, case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: default: /* other type */ - pnp_warn("unknown resource type %d", resource->type); + dev_warn(&dev->dev, "can't encode unknown resource " + "type %d\n", resource->type); return -EINVAL; } resource++; diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile index 3cd3ed760605..310e2b3a7710 100644 --- a/drivers/pnp/pnpbios/Makefile +++ b/drivers/pnp/pnpbios/Makefile @@ -5,3 +5,7 @@ pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y) + +ifeq ($(CONFIG_PNP_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index a8364d815222..7ff824496b39 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -7,7 +7,6 @@ #include <linux/init.h> #include <linux/linkage.h> #include <linux/kernel.h> -#include <linux/pnpbios.h> #include <linux/device.h> #include <linux/pnp.h> #include <linux/mm.h> diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index a8a51500e1e9..19a4be1a9a31 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -50,7 +50,6 @@ #include <linux/init.h> #include <linux/linkage.h> #include <linux/kernel.h> -#include <linux/pnpbios.h> #include <linux/device.h> #include <linux/pnp.h> #include <linux/mm.h> @@ -69,6 +68,7 @@ #include <asm/system.h> #include <asm/byteorder.h> +#include "../base.h" #include "pnpbios.h" /* @@ -203,8 +203,7 @@ static int pnp_dock_thread(void *unused) #endif /* CONFIG_HOTPLUG */ -static int pnpbios_get_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpbios_get_resources(struct pnp_dev *dev) { u8 nodenum = dev->number; struct pnp_bios_node *node; @@ -212,6 +211,7 @@ static int pnpbios_get_resources(struct pnp_dev *dev, if (!pnpbios_is_dynamic(dev)) return -EPERM; + dev_dbg(&dev->dev, "get resources\n"); node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; @@ -219,14 +219,13 @@ static int pnpbios_get_resources(struct pnp_dev *dev, kfree(node); return -ENODEV; } - pnpbios_read_resources_from_node(res, node); + pnpbios_read_resources_from_node(dev, node); dev->active = pnp_is_active(dev); kfree(node); return 0; } -static int pnpbios_set_resources(struct pnp_dev *dev, - struct pnp_resource_table *res) +static int pnpbios_set_resources(struct pnp_dev *dev) { u8 nodenum = dev->number; struct pnp_bios_node *node; @@ -235,6 +234,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev, if (!pnpbios_is_dynamic(dev)) return -EPERM; + dev_dbg(&dev->dev, "set resources\n"); node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; @@ -242,7 +242,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev, kfree(node); return -ENODEV; } - if (pnpbios_write_resources_to_node(res, node) < 0) { + if (pnpbios_write_resources_to_node(dev, node) < 0) { kfree(node); return -1; } @@ -317,7 +317,6 @@ static int __init insert_device(struct pnp_bios_node *node) { struct list_head *pos; struct pnp_dev *dev; - struct pnp_id *dev_id; char id[8]; /* check if the device is already added */ @@ -327,20 +326,11 @@ static int __init insert_device(struct pnp_bios_node *node) return -1; } - dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL); + pnp_eisa_id_to_string(node->eisa_id & PNP_EISA_ID_MASK, id); + dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id); if (!dev) return -1; - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); - if (!dev_id) { - kfree(dev); - return -1; - } - - dev->number = node->handle; - pnpid32_to_pnpid(node->eisa_id, id); - memcpy(dev_id->id, id, 7); - pnp_add_id(dev_id, dev); pnpbios_parse_data_stream(dev, node); dev->active = pnp_is_active(dev); dev->flags = node->flags; @@ -353,11 +343,10 @@ static int __init insert_device(struct pnp_bios_node *node) dev->capabilities |= PNP_WRITE; if (dev->flags & PNPBIOS_REMOVABLE) dev->capabilities |= PNP_REMOVABLE; - dev->protocol = &pnpbios_protocol; /* clear out the damaged flags */ if (!dev->active) - pnp_init_resource_table(&dev->res); + pnp_init_resources(dev); pnp_add_device(dev); pnpbios_interface_attach_device(node); diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h index d8cb2fd1f127..b09cf6dc2075 100644 --- a/drivers/pnp/pnpbios/pnpbios.h +++ b/drivers/pnp/pnpbios/pnpbios.h @@ -2,6 +2,142 @@ * pnpbios.h - contains local definitions */ +/* + * Include file for the interface to a PnP BIOS + * + * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de) + * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk> + * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Return codes + */ +#define PNP_SUCCESS 0x00 +#define PNP_NOT_SET_STATICALLY 0x7f +#define PNP_UNKNOWN_FUNCTION 0x81 +#define PNP_FUNCTION_NOT_SUPPORTED 0x82 +#define PNP_INVALID_HANDLE 0x83 +#define PNP_BAD_PARAMETER 0x84 +#define PNP_SET_FAILED 0x85 +#define PNP_EVENTS_NOT_PENDING 0x86 +#define PNP_SYSTEM_NOT_DOCKED 0x87 +#define PNP_NO_ISA_PNP_CARDS 0x88 +#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89 +#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a +#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b +#define PNP_BUFFER_TOO_SMALL 0x8c +#define PNP_USE_ESCD_SUPPORT 0x8d +#define PNP_MESSAGE_NOT_SUPPORTED 0x8e +#define PNP_HARDWARE_ERROR 0x8f + +#define ESCD_SUCCESS 0x00 +#define ESCD_IO_ERROR_READING 0x55 +#define ESCD_INVALID 0x56 +#define ESCD_BUFFER_TOO_SMALL 0x59 +#define ESCD_NVRAM_TOO_SMALL 0x5a +#define ESCD_FUNCTION_NOT_SUPPORTED 0x81 + +/* + * Events that can be received by "get event" + */ +#define PNPEV_ABOUT_TO_CHANGE_CONFIG 0x0001 +#define PNPEV_DOCK_CHANGED 0x0002 +#define PNPEV_SYSTEM_DEVICE_CHANGED 0x0003 +#define PNPEV_CONFIG_CHANGED_FAILED 0x0004 +#define PNPEV_UNKNOWN_SYSTEM_EVENT 0xffff +/* 0x8000 through 0xfffe are OEM defined */ + +/* + * Messages that should be sent through "send message" + */ +#define PNPMSG_OK 0x00 +#define PNPMSG_ABORT 0x01 +#define PNPMSG_UNDOCK_DEFAULT_ACTION 0x40 +#define PNPMSG_POWER_OFF 0x41 +#define PNPMSG_PNP_OS_ACTIVE 0x42 +#define PNPMSG_PNP_OS_INACTIVE 0x43 + +/* + * Plug and Play BIOS flags + */ +#define PNPBIOS_NO_DISABLE 0x0001 +#define PNPBIOS_NO_CONFIG 0x0002 +#define PNPBIOS_OUTPUT 0x0004 +#define PNPBIOS_INPUT 0x0008 +#define PNPBIOS_BOOTABLE 0x0010 +#define PNPBIOS_DOCK 0x0020 +#define PNPBIOS_REMOVABLE 0x0040 +#define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000) +#define pnpbios_is_dynamic(x) ((x)->flags & 0x0080) + +/* + * Function Parameters + */ +#define PNPMODE_STATIC 1 +#define PNPMODE_DYNAMIC 0 + +/* 0x8000 through 0xffff are OEM defined */ + +#pragma pack(1) +struct pnp_dev_node_info { + __u16 no_nodes; + __u16 max_node_size; +}; +struct pnp_docking_station_info { + __u32 location_id; + __u32 serial; + __u16 capabilities; +}; +struct pnp_isa_config_struc { + __u8 revision; + __u8 no_csns; + __u16 isa_rd_data_port; + __u16 reserved; +}; +struct escd_info_struc { + __u16 min_escd_write_size; + __u16 escd_size; + __u32 nv_storage_base; +}; +struct pnp_bios_node { + __u16 size; + __u8 handle; + __u32 eisa_id; + __u8 type_code[3]; + __u16 flags; + __u8 data[0]; +}; +#pragma pack() + +/* non-exported */ +extern struct pnp_dev_node_info node_info; + +extern int pnp_bios_dev_node_info(struct pnp_dev_node_info *data); +extern int pnp_bios_get_dev_node(u8 *nodenum, char config, + struct pnp_bios_node *data); +extern int pnp_bios_set_dev_node(u8 nodenum, char config, + struct pnp_bios_node *data); +extern int pnp_bios_get_stat_res(char *info); +extern int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data); +extern int pnp_bios_escd_info(struct escd_info_struc *data); +extern int pnp_bios_read_escd(char *data, u32 nvram_base); +extern int pnp_bios_dock_station_info(struct pnp_docking_station_info *data); + #pragma pack(1) union pnp_bios_install_struct { struct { @@ -28,8 +164,8 @@ extern int pnp_bios_present(void); extern int pnpbios_dont_use_current_config; extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node); -extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node); -extern int pnpbios_write_resources_to_node(struct pnp_resource_table *res, struct pnp_bios_node * node); +extern int pnpbios_read_resources_from_node(struct pnp_dev *dev, struct pnp_bios_node *node); +extern int pnpbios_write_resources_to_node(struct pnp_dev *dev, struct pnp_bios_node *node); extern void pnpid32_to_pnpid(u32 id, char *str); extern void pnpbios_print_status(const char * module, u16 status); diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index bb19bc957bad..b35d921bac6e 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -23,7 +23,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/proc_fs.h> -#include <linux/pnpbios.h> +#include <linux/pnp.h> #include <linux/init.h> #include <asm/uaccess.h> @@ -256,7 +256,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node *node) */ int __init pnpbios_proc_init(void) { - proc_pnp = proc_mkdir("pnp", proc_bus); + proc_pnp = proc_mkdir("bus/pnp", NULL); if (!proc_pnp) return -EIO; proc_pnp_boot = proc_mkdir("boot", proc_pnp); @@ -294,5 +294,5 @@ void __exit pnpbios_proc_exit(void) remove_proc_entry("configuration_info", proc_pnp); remove_proc_entry("devices", proc_pnp); remove_proc_entry("boot", proc_pnp); - remove_proc_entry("pnp", proc_bus); + remove_proc_entry("bus/pnp", NULL); } diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index caade3531416..5ff9a4c0447e 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -4,7 +4,6 @@ #include <linux/ctype.h> #include <linux/pnp.h> -#include <linux/pnpbios.h> #include <linux/string.h> #include <linux/slab.h> @@ -16,6 +15,7 @@ inline void pcibios_penalize_isa_irq(int irq, int active) } #endif /* CONFIG_PCI */ +#include "../base.h" #include "pnpbios.h" /* standard resource tags */ @@ -53,97 +53,43 @@ inline void pcibios_penalize_isa_irq(int irq, int active) * Allocated Resources */ -static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res, - int irq) +static void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev, + int start, int len) { - int i = 0; - - while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) - && i < PNP_MAX_IRQ) - i++; - if (i < PNP_MAX_IRQ) { - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag - if (irq == -1) { - res->irq_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->irq_resource[i].start = - res->irq_resource[i].end = (unsigned long)irq; - pcibios_penalize_isa_irq(irq, 1); - } -} + int flags = 0; + int end = start + len - 1; -static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res, - int dma) -{ - int i = 0; - - while (i < PNP_MAX_DMA && - !(res->dma_resource[i].flags & IORESOURCE_UNSET)) - i++; - if (i < PNP_MAX_DMA) { - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag - if (dma == -1) { - res->dma_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->dma_resource[i].start = - res->dma_resource[i].end = (unsigned long)dma; - } -} + if (len <= 0 || end >= 0x10003) + flags |= IORESOURCE_DISABLED; -static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res, - int io, int len) -{ - int i = 0; - - while (!(res->port_resource[i].flags & IORESOURCE_UNSET) - && i < PNP_MAX_PORT) - i++; - if (i < PNP_MAX_PORT) { - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag - if (len <= 0 || (io + len - 1) >= 0x10003) { - res->port_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->port_resource[i].start = (unsigned long)io; - res->port_resource[i].end = (unsigned long)(io + len - 1); - } + pnp_add_io_resource(dev, start, end, flags); } -static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res, - int mem, int len) +static void pnpbios_parse_allocated_memresource(struct pnp_dev *dev, + int start, int len) { - int i = 0; - - while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) - && i < PNP_MAX_MEM) - i++; - if (i < PNP_MAX_MEM) { - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag - if (len <= 0) { - res->mem_resource[i].flags |= IORESOURCE_DISABLED; - return; - } - res->mem_resource[i].start = (unsigned long)mem; - res->mem_resource[i].end = (unsigned long)(mem + len - 1); - } + int flags = 0; + int end = start + len - 1; + + if (len <= 0) + flags |= IORESOURCE_DISABLED; + + pnp_add_mem_resource(dev, start, end, flags); } -static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, - unsigned char *end, - struct - pnp_resource_table - *res) +static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev, + unsigned char *p, + unsigned char *end) { unsigned int len, tag; - int io, size, mask, i; + int io, size, mask, i, flags; if (!p) return NULL; - /* Blank the resource table values */ - pnp_init_resource_table(res); + dev_dbg(&dev->dev, "parse allocated resources\n"); + + pnp_init_resources(dev); while ((char *)p < (char *)end) { @@ -163,7 +109,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = *(short *)&p[4]; size = *(short *)&p[10]; - pnpbios_parse_allocated_memresource(res, io, size); + pnpbios_parse_allocated_memresource(dev, io, size); break; case LARGE_TAG_ANSISTR: @@ -179,7 +125,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = *(int *)&p[4]; size = *(int *)&p[16]; - pnpbios_parse_allocated_memresource(res, io, size); + pnpbios_parse_allocated_memresource(dev, io, size); break; case LARGE_TAG_FIXEDMEM32: @@ -187,29 +133,37 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = *(int *)&p[4]; size = *(int *)&p[8]; - pnpbios_parse_allocated_memresource(res, io, size); + pnpbios_parse_allocated_memresource(dev, io, size); break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; + flags = 0; io = -1; mask = p[1] + p[2] * 256; for (i = 0; i < 16; i++, mask = mask >> 1) if (mask & 0x01) io = i; - pnpbios_parse_allocated_irqresource(res, io); + if (io != -1) + pcibios_penalize_isa_irq(io, 1); + else + flags = IORESOURCE_DISABLED; + pnp_add_irq_resource(dev, io, flags); break; case SMALL_TAG_DMA: if (len != 2) goto len_err; + flags = 0; io = -1; mask = p[1]; for (i = 0; i < 8; i++, mask = mask >> 1) if (mask & 0x01) io = i; - pnpbios_parse_allocated_dmaresource(res, io); + if (io == -1) + flags = IORESOURCE_DISABLED; + pnp_add_dma_resource(dev, io, flags); break; case SMALL_TAG_PORT: @@ -217,7 +171,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = p[2] + p[3] * 256; size = p[7]; - pnpbios_parse_allocated_ioresource(res, io, size); + pnpbios_parse_allocated_ioresource(dev, io, size); break; case SMALL_TAG_VENDOR: @@ -229,7 +183,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, goto len_err; io = p[1] + p[2] * 256; size = p[3]; - pnpbios_parse_allocated_ioresource(res, io, size); + pnpbios_parse_allocated_ioresource(dev, io, size); break; case SMALL_TAG_END: @@ -239,9 +193,8 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag %#x length %d\n", + tag, len); break; } @@ -252,8 +205,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -262,7 +214,8 @@ len_err: * Resource Configuration Options */ -static __init void pnpbios_parse_mem_option(unsigned char *p, int size, +static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, + unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem *mem; @@ -275,10 +228,11 @@ static __init void pnpbios_parse_mem_option(unsigned char *p, int size, mem->align = (p[9] << 8) | p[8]; mem->size = ((p[11] << 8) | p[10]) << 8; mem->flags = p[3]; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } -static __init void pnpbios_parse_mem32_option(unsigned char *p, int size, +static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, + unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem *mem; @@ -291,10 +245,11 @@ static __init void pnpbios_parse_mem32_option(unsigned char *p, int size, mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; mem->flags = p[3]; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } -static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, +static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, + unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem *mem; @@ -306,11 +261,12 @@ static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; mem->align = 0; mem->flags = p[3]; - pnp_register_mem_resource(option, mem); + pnp_register_mem_resource(dev, option, mem); } -static __init void pnpbios_parse_irq_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, + unsigned char *p, int size, + struct pnp_option *option) { struct pnp_irq *irq; unsigned long bits; @@ -324,11 +280,12 @@ static __init void pnpbios_parse_irq_option(unsigned char *p, int size, irq->flags = p[3]; else irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_register_irq_resource(option, irq); + pnp_register_irq_resource(dev, option, irq); } -static __init void pnpbios_parse_dma_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_dma_option(struct pnp_dev *dev, + unsigned char *p, int size, + struct pnp_option *option) { struct pnp_dma *dma; @@ -337,10 +294,11 @@ static __init void pnpbios_parse_dma_option(unsigned char *p, int size, return; dma->map = p[1]; dma->flags = p[2]; - pnp_register_dma_resource(option, dma); + pnp_register_dma_resource(dev, option, dma); } -static __init void pnpbios_parse_port_option(unsigned char *p, int size, +static __init void pnpbios_parse_port_option(struct pnp_dev *dev, + unsigned char *p, int size, struct pnp_option *option) { struct pnp_port *port; @@ -353,10 +311,11 @@ static __init void pnpbios_parse_port_option(unsigned char *p, int size, port->align = p[6]; port->size = p[7]; port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } -static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size, +static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, + unsigned char *p, int size, struct pnp_option *option) { struct pnp_port *port; @@ -368,7 +327,7 @@ static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size, port->size = p[3]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_register_port_resource(option, port); + pnp_register_port_resource(dev, option, port); } static __init unsigned char * @@ -382,6 +341,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, if (!p) return NULL; + dev_dbg(&dev->dev, "parse resource options\n"); + option_independent = option = pnp_register_independent_option(dev); if (!option) return NULL; @@ -402,37 +363,37 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, case LARGE_TAG_MEM: if (len != 9) goto len_err; - pnpbios_parse_mem_option(p, len, option); + pnpbios_parse_mem_option(dev, p, len, option); break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; - pnpbios_parse_mem32_option(p, len, option); + pnpbios_parse_mem32_option(dev, p, len, option); break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; - pnpbios_parse_fixed_mem32_option(p, len, option); + pnpbios_parse_fixed_mem32_option(dev, p, len, option); break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; - pnpbios_parse_irq_option(p, len, option); + pnpbios_parse_irq_option(dev, p, len, option); break; case SMALL_TAG_DMA: if (len != 2) goto len_err; - pnpbios_parse_dma_option(p, len, option); + pnpbios_parse_dma_option(dev, p, len, option); break; case SMALL_TAG_PORT: if (len != 7) goto len_err; - pnpbios_parse_port_option(p, len, option); + pnpbios_parse_port_option(dev, p, len, option); break; case SMALL_TAG_VENDOR: @@ -442,7 +403,7 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; - pnpbios_parse_fixed_port_option(p, len, option); + pnpbios_parse_fixed_port_option(dev, p, len, option); break; case SMALL_TAG_STARTDEP: @@ -460,9 +421,10 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, if (len != 0) goto len_err; if (option_independent == option) - printk(KERN_WARNING - "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n"); + dev_warn(&dev->dev, "missing " + "SMALL_TAG_STARTDEP tag\n"); option = option_independent; + dev_dbg(&dev->dev, "end dependent options\n"); break; case SMALL_TAG_END: @@ -470,9 +432,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag %#x length %d\n", + tag, len); break; } @@ -483,8 +444,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -493,32 +453,12 @@ len_err: * Compatible Device IDs */ -#define HEX(id,a) hex[((id)>>a) & 15] -#define CHAR(id,a) (0x40 + (((id)>>a) & 31)) - -void pnpid32_to_pnpid(u32 id, char *str) -{ - const char *hex = "0123456789abcdef"; - - id = be32_to_cpu(id); - str[0] = CHAR(id, 26); - str[1] = CHAR(id, 21); - str[2] = CHAR(id, 16); - str[3] = HEX(id, 12); - str[4] = HEX(id, 8); - str[5] = HEX(id, 4); - str[6] = HEX(id, 0); - str[7] = '\0'; -} - -#undef CHAR -#undef HEX - static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev) { int len, tag; + u32 eisa_id; char id[8]; struct pnp_id *dev_id; @@ -548,13 +488,11 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, case SMALL_TAG_COMPATDEVID: /* compatible ID */ if (len != 4) goto len_err; - dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); + eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24; + pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id); + dev_id = pnp_add_id(dev, id); if (!dev_id) return NULL; - pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << - 24, id); - memcpy(&dev_id->id, id, 7); - pnp_add_id(dev_id, dev); break; case SMALL_TAG_END: @@ -564,9 +502,8 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag %#x length %d\n", + tag, len); break; } @@ -577,8 +514,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -587,7 +523,8 @@ len_err: * Allocated Resource Encoding */ -static void pnpbios_encode_mem(unsigned char *p, struct resource *res) +static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; @@ -598,9 +535,13 @@ static void pnpbios_encode_mem(unsigned char *p, struct resource *res) p[7] = ((base >> 8) >> 8) & 0xff; p[10] = (len >> 8) & 0xff; p[11] = ((len >> 8) >> 8) & 0xff; + + dev_dbg(&dev->dev, " encode mem %#llx-%#llx\n", + (unsigned long long) res->start, (unsigned long long) res->end); } -static void pnpbios_encode_mem32(unsigned char *p, struct resource *res) +static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; @@ -617,9 +558,13 @@ static void pnpbios_encode_mem32(unsigned char *p, struct resource *res) p[17] = (len >> 8) & 0xff; p[18] = (len >> 16) & 0xff; p[19] = (len >> 24) & 0xff; + + dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx\n", + (unsigned long long) res->start, (unsigned long long) res->end); } -static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res) +static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; @@ -632,26 +577,38 @@ static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res) p[9] = (len >> 8) & 0xff; p[10] = (len >> 16) & 0xff; p[11] = (len >> 24) & 0xff; + + dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx\n", + (unsigned long long) res->start, (unsigned long long) res->end); } -static void pnpbios_encode_irq(unsigned char *p, struct resource *res) +static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long map = 0; map = 1 << res->start; p[1] = map & 0xff; p[2] = (map >> 8) & 0xff; + + dev_dbg(&dev->dev, " encode irq %llu\n", + (unsigned long long)res->start); } -static void pnpbios_encode_dma(unsigned char *p, struct resource *res) +static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long map = 0; map = 1 << res->start; p[1] = map & 0xff; + + dev_dbg(&dev->dev, " encode dma %llu\n", + (unsigned long long)res->start); } -static void pnpbios_encode_port(unsigned char *p, struct resource *res) +static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; @@ -661,9 +618,13 @@ static void pnpbios_encode_port(unsigned char *p, struct resource *res) p[4] = base & 0xff; p[5] = (base >> 8) & 0xff; p[7] = len & 0xff; + + dev_dbg(&dev->dev, " encode io %#llx-%#llx\n", + (unsigned long long) res->start, (unsigned long long) res->end); } -static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res) +static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p, + struct resource *res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; @@ -671,13 +632,15 @@ static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res) p[1] = base & 0xff; p[2] = (base >> 8) & 0xff; p[3] = len & 0xff; + + dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n", + (unsigned long long) res->start, (unsigned long long) res->end); } -static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, - unsigned char *end, - struct - pnp_resource_table - *res) +static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev + *dev, + unsigned char *p, + unsigned char *end) { unsigned int len, tag; int port = 0, irq = 0, dma = 0, mem = 0; @@ -701,42 +664,48 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, case LARGE_TAG_MEM: if (len != 9) goto len_err; - pnpbios_encode_mem(p, &res->mem_resource[mem]); + pnpbios_encode_mem(dev, p, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; - pnpbios_encode_mem32(p, &res->mem_resource[mem]); + pnpbios_encode_mem32(dev, p, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; - pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]); + pnpbios_encode_fixed_mem32(dev, p, + pnp_get_resource(dev, IORESOURCE_MEM, mem)); mem++; break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; - pnpbios_encode_irq(p, &res->irq_resource[irq]); + pnpbios_encode_irq(dev, p, + pnp_get_resource(dev, IORESOURCE_IRQ, irq)); irq++; break; case SMALL_TAG_DMA: if (len != 2) goto len_err; - pnpbios_encode_dma(p, &res->dma_resource[dma]); + pnpbios_encode_dma(dev, p, + pnp_get_resource(dev, IORESOURCE_DMA, dma)); dma++; break; case SMALL_TAG_PORT: if (len != 7) goto len_err; - pnpbios_encode_port(p, &res->port_resource[port]); + pnpbios_encode_port(dev, p, + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; @@ -747,7 +716,8 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; - pnpbios_encode_fixed_port(p, &res->port_resource[port]); + pnpbios_encode_fixed_port(dev, p, + pnp_get_resource(dev, IORESOURCE_IO, port)); port++; break; @@ -758,9 +728,8 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p, default: /* an unkown tag */ len_err: - printk(KERN_ERR - "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", - tag, len); + dev_err(&dev->dev, "unknown tag %#x length %d\n", + tag, len); break; } @@ -771,8 +740,7 @@ len_err: p += len + 1; } - printk(KERN_ERR - "PnPBIOS: Resource structure does not contain an end tag.\n"); + dev_err(&dev->dev, "no end tag in resource structure\n"); return NULL; } @@ -787,7 +755,7 @@ int __init pnpbios_parse_data_stream(struct pnp_dev *dev, unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); - p = pnpbios_parse_allocated_resource_data(p, end, &dev->res); + p = pnpbios_parse_allocated_resource_data(dev, p, end); if (!p) return -EIO; p = pnpbios_parse_resource_option_data(p, end, dev); @@ -799,25 +767,25 @@ int __init pnpbios_parse_data_stream(struct pnp_dev *dev, return 0; } -int pnpbios_read_resources_from_node(struct pnp_resource_table *res, +int pnpbios_read_resources_from_node(struct pnp_dev *dev, struct pnp_bios_node *node) { unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); - p = pnpbios_parse_allocated_resource_data(p, end, res); + p = pnpbios_parse_allocated_resource_data(dev, p, end); if (!p) return -EIO; return 0; } -int pnpbios_write_resources_to_node(struct pnp_resource_table *res, +int pnpbios_write_resources_to_node(struct pnp_dev *dev, struct pnp_bios_node *node) { unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); - p = pnpbios_encode_allocated_resource_data(p, end, res); + p = pnpbios_encode_allocated_resource_data(dev, p, end); if (!p) return -EIO; return 0; diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 37993206ae5d..d049a2279fea 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -49,8 +49,11 @@ static void quirk_awe32_resources(struct pnp_dev *dev) port2->max += 0x400; port3->min += 0x800; port3->max += 0x800; + dev_info(&dev->dev, + "AWE32 quirk - added ioports 0x%lx and 0x%lx\n", + (unsigned long)port2->min, + (unsigned long)port3->min); } - printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n"); } static void quirk_cmi8330_resources(struct pnp_dev *dev) @@ -73,7 +76,8 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) IORESOURCE_DMA_8BIT) dma->map = 0x000A; } - printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n"); + dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 " + "and DMA channels to 1, 3\n"); } static void quirk_sb16audio_resources(struct pnp_dev *dev) @@ -104,8 +108,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) changed = 1; } if (changed) - printk(KERN_INFO - "pnp: SB audio device quirk - increasing port range\n"); + dev_info(&dev->dev, "SB audio device quirk - increased port range\n"); } @@ -114,6 +117,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) static void quirk_system_pci_resources(struct pnp_dev *dev) { struct pci_dev *pdev = NULL; + struct resource *res; resource_size_t pnp_start, pnp_end, pci_start, pci_end; int i, j; @@ -134,13 +138,15 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) pci_start = pci_resource_start(pdev, i); pci_end = pci_resource_end(pdev, i); - for (j = 0; j < PNP_MAX_MEM; j++) { - if (!pnp_mem_valid(dev, j) || - pnp_mem_len(dev, j) == 0) + for (j = 0; + (res = pnp_get_resource(dev, IORESOURCE_MEM, j)); + j++) { + if (res->flags & IORESOURCE_UNSET || + (res->start == 0 && res->end == 0)) continue; - pnp_start = pnp_mem_start(dev, j); - pnp_end = pnp_mem_end(dev, j); + pnp_start = res->start; + pnp_end = res->end; /* * If the PNP region doesn't overlap the PCI @@ -173,7 +179,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) pci_name(pdev), i, (unsigned long long) pci_start, (unsigned long long) pci_end); - pnp_mem_flags(dev, j) = 0; + res->flags = 0; } } } @@ -214,8 +220,8 @@ void pnp_fixup_device(struct pnp_dev *dev) quirk = pnp_fixups[i].quirk_function; #ifdef DEBUG - dev_dbg(&dev->dev, "calling quirk 0x%p", quirk); - print_fn_descriptor_symbol(": %s()\n", + dev_dbg(&dev->dev, "calling "); + print_fn_descriptor_symbol("%s()\n", (unsigned long) *quirk); #endif (*quirk)(dev); diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index e50ebcffb962..2041620d5682 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -53,6 +53,8 @@ struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) if (dev->independent) dev_err(&dev->dev, "independent resource already registered\n"); dev->independent = option; + + dev_dbg(&dev->dev, "new independent option\n"); return option; } @@ -70,12 +72,18 @@ struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, parent->next = option; } else dev->dependent = option; + + dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority); return option; } -int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) +int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_irq *data) { struct pnp_irq *ptr; +#ifdef DEBUG + char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */ +#endif ptr = option->irq; while (ptr && ptr->next) @@ -94,10 +102,17 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) pcibios_penalize_isa_irq(i, 0); } #endif + +#ifdef DEBUG + bitmap_scnprintf(buf, sizeof(buf), data->map, PNP_IRQ_NR); + dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf, + data->flags); +#endif return 0; } -int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) +int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_dma *data) { struct pnp_dma *ptr; @@ -109,10 +124,13 @@ int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) else option->dma = data; + dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map, + data->flags); return 0; } -int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) +int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_port *data) { struct pnp_port *ptr; @@ -124,10 +142,14 @@ int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) else option->port = data; + dev_dbg(&dev->dev, " io " + "min %#x max %#x align %d size %d flags %#x\n", + data->min, data->max, data->align, data->size, data->flags); return 0; } -int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) +int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_mem *data) { struct pnp_mem *ptr; @@ -138,6 +160,10 @@ int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) ptr->next = data; else option->mem = data; + + dev_dbg(&dev->dev, " mem " + "min %#x max %#x align %d size %d flags %#x\n", + data->min, data->max, data->align, data->size, data->flags); return 0; } @@ -213,17 +239,18 @@ void pnp_free_option(struct pnp_option *option) #define cannot_compare(flags) \ ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) -int pnp_check_port(struct pnp_dev *dev, int idx) +int pnp_check_port(struct pnp_dev *dev, struct resource *res) { - int tmp; + int i; struct pnp_dev *tdev; + struct resource *tres; resource_size_t *port, *end, *tport, *tend; - port = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; + port = &res->start; + end = &res->end; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.port_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is already in use, skip if the @@ -234,18 +261,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx) } /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - int rport = pnp_reserve_io[tmp << 1]; - int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1; + for (i = 0; i < 8; i++) { + int rport = pnp_reserve_io[i << 1]; + int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1; if (ranged_conflict(port, end, &rport, &rend)) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) { - if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) { - tport = &dev->res.port_resource[tmp].start; - tend = &dev->res.port_resource[tmp].end; + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_IO) { + tport = &tres->start; + tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) return 0; } @@ -255,13 +282,14 @@ int pnp_check_port(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { - if (cannot_compare - (tdev->res.port_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_IO, i)); + i++) { + if (tres->flags & IORESOURCE_IO) { + if (cannot_compare(tres->flags)) continue; - tport = &tdev->res.port_resource[tmp].start; - tend = &tdev->res.port_resource[tmp].end; + tport = &tres->start; + tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) return 0; } @@ -271,17 +299,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx) return 1; } -int pnp_check_mem(struct pnp_dev *dev, int idx) +int pnp_check_mem(struct pnp_dev *dev, struct resource *res) { - int tmp; + int i; struct pnp_dev *tdev; + struct resource *tres; resource_size_t *addr, *end, *taddr, *tend; - addr = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; + addr = &res->start; + end = &res->end; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.mem_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is already in use, skip if the @@ -292,18 +321,18 @@ int pnp_check_mem(struct pnp_dev *dev, int idx) } /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - int raddr = pnp_reserve_mem[tmp << 1]; - int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1; + for (i = 0; i < 8; i++) { + int raddr = pnp_reserve_mem[i << 1]; + int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1; if (ranged_conflict(addr, end, &raddr, &rend)) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) { - if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - taddr = &dev->res.mem_resource[tmp].start; - tend = &dev->res.mem_resource[tmp].end; + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_MEM) { + taddr = &tres->start; + tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) return 0; } @@ -313,13 +342,14 @@ int pnp_check_mem(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - if (cannot_compare - (tdev->res.mem_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i)); + i++) { + if (tres->flags & IORESOURCE_MEM) { + if (cannot_compare(tres->flags)) continue; - taddr = &tdev->res.mem_resource[tmp].start; - tend = &tdev->res.mem_resource[tmp].end; + taddr = &tres->start; + tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) return 0; } @@ -334,14 +364,17 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int pnp_check_irq(struct pnp_dev *dev, int idx) +int pnp_check_irq(struct pnp_dev *dev, struct resource *res) { - int tmp; + int i; struct pnp_dev *tdev; - resource_size_t *irq = &dev->res.irq_resource[idx].start; + struct resource *tres; + resource_size_t *irq; + + irq = &res->start; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.irq_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is valid */ @@ -349,15 +382,15 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) return 0; /* check if the resource is reserved */ - for (tmp = 0; tmp < 16; tmp++) { - if (pnp_reserve_irq[tmp] == *irq) + for (i = 0; i < 16; i++) { + if (pnp_reserve_irq[i] == *irq) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) { - if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if (dev->res.irq_resource[tmp].start == *irq) + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_IRQ) { + if (tres->start == *irq) return 0; } } @@ -388,12 +421,13 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if (cannot_compare - (tdev->res.irq_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i)); + i++) { + if (tres->flags & IORESOURCE_IRQ) { + if (cannot_compare(tres->flags)) continue; - if ((tdev->res.irq_resource[tmp].start == *irq)) + if (tres->start == *irq) return 0; } } @@ -402,15 +436,18 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) return 1; } -int pnp_check_dma(struct pnp_dev *dev, int idx) +int pnp_check_dma(struct pnp_dev *dev, struct resource *res) { #ifndef CONFIG_IA64 - int tmp; + int i; struct pnp_dev *tdev; - resource_size_t *dma = &dev->res.dma_resource[idx].start; + struct resource *tres; + resource_size_t *dma; + + dma = &res->start; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.dma_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is valid */ @@ -418,15 +455,15 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) return 0; /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - if (pnp_reserve_dma[tmp] == *dma) + for (i = 0; i < 8; i++) { + if (pnp_reserve_dma[i] == *dma) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) { - if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if (dev->res.dma_resource[tmp].start == *dma) + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_DMA) { + if (tres->start == *dma) return 0; } } @@ -443,12 +480,13 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if (cannot_compare - (tdev->res.dma_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i)); + i++) { + if (tres->flags & IORESOURCE_DMA) { + if (cannot_compare(tres->flags)) continue; - if ((tdev->res.dma_resource[tmp].start == *dma)) + if (tres->start == *dma) return 0; } } @@ -461,6 +499,193 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) #endif } +struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev, + unsigned int type, unsigned int num) +{ + struct pnp_resource_table *res = dev->res; + + switch (type) { + case IORESOURCE_IO: + if (num >= PNP_MAX_PORT) + return NULL; + return &res->port[num]; + case IORESOURCE_MEM: + if (num >= PNP_MAX_MEM) + return NULL; + return &res->mem[num]; + case IORESOURCE_IRQ: + if (num >= PNP_MAX_IRQ) + return NULL; + return &res->irq[num]; + case IORESOURCE_DMA: + if (num >= PNP_MAX_DMA) + return NULL; + return &res->dma[num]; + } + return NULL; +} + +struct resource *pnp_get_resource(struct pnp_dev *dev, + unsigned int type, unsigned int num) +{ + struct pnp_resource *pnp_res; + + pnp_res = pnp_get_pnp_resource(dev, type, num); + if (pnp_res) + return &pnp_res->res; + + return NULL; +} +EXPORT_SYMBOL(pnp_get_resource); + +static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev, int type) +{ + struct pnp_resource *pnp_res; + int i; + + switch (type) { + case IORESOURCE_IO: + for (i = 0; i < PNP_MAX_PORT; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + case IORESOURCE_MEM: + for (i = 0; i < PNP_MAX_MEM; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + case IORESOURCE_IRQ: + for (i = 0; i < PNP_MAX_IRQ; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + case IORESOURCE_DMA: + for (i = 0; i < PNP_MAX_DMA; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + } + return NULL; +} + +struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, + int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_IRQ); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for IRQ %d\n", + irq); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_IRQ | flags; + res->start = irq; + res->end = irq; + + dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags); + return pnp_res; +} + +struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, + int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_DMA); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for DMA %d\n", + dma); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_DMA | flags; + res->start = dma; + res->end = dma; + + dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags); + return pnp_res; +} + +struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end, int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_IO); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for IO " + "%#llx-%#llx\n",(unsigned long long) start, + (unsigned long long) end); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_IO | flags; + res->start = start; + res->end = end; + + dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n", + (unsigned long long) start, (unsigned long long) end, flags); + return pnp_res; +} + +struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end, int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_MEM); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for MEM " + "%#llx-%#llx\n",(unsigned long long) start, + (unsigned long long) end); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_MEM | flags; + res->start = start; + res->end = end; + + dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n", + (unsigned long long) start, (unsigned long long) end, flags); + return pnp_res; +} + /* format is: pnp_reserve_irq=irq1[,irq2] .... */ static int __init pnp_setup_reserve_irq(char *str) { diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index 13c608f5fb30..3eba85ed729c 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -25,3 +25,66 @@ int pnp_is_active(struct pnp_dev *dev) } EXPORT_SYMBOL(pnp_is_active); + +/* + * Functionally similar to acpi_ex_eisa_id_to_string(), but that's + * buried in the ACPI CA, and we can't depend on it being present. + */ +void pnp_eisa_id_to_string(u32 id, char *str) +{ + id = be32_to_cpu(id); + + /* + * According to the specs, the first three characters are five-bit + * compressed ASCII, and the left-over high order bit should be zero. + * However, the Linux ISAPNP code historically used six bits for the + * first character, and there seem to be IDs that depend on that, + * e.g., "nEC8241" in the Linux 8250_pnp serial driver and the + * FreeBSD sys/pc98/cbus/sio_cbus.c driver. + */ + str[0] = 'A' + ((id >> 26) & 0x3f) - 1; + str[1] = 'A' + ((id >> 21) & 0x1f) - 1; + str[2] = 'A' + ((id >> 16) & 0x1f) - 1; + str[3] = hex_asc((id >> 12) & 0xf); + str[4] = hex_asc((id >> 8) & 0xf); + str[5] = hex_asc((id >> 4) & 0xf); + str[6] = hex_asc((id >> 0) & 0xf); + str[7] = '\0'; +} + +void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) +{ +#ifdef DEBUG + struct resource *res; + int i; + + dev_dbg(&dev->dev, "current resources: %s\n", desc); + + for (i = 0; i < PNP_MAX_IRQ; i++) { + res = pnp_get_resource(dev, IORESOURCE_IRQ, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + dev_dbg(&dev->dev, " irq %lld flags %#lx\n", + (unsigned long long) res->start, res->flags); + } + for (i = 0; i < PNP_MAX_DMA; i++) { + res = pnp_get_resource(dev, IORESOURCE_DMA, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + dev_dbg(&dev->dev, " dma %lld flags %#lx\n", + (unsigned long long) res->start, res->flags); + } + for (i = 0; i < PNP_MAX_PORT; i++) { + res = pnp_get_resource(dev, IORESOURCE_IO, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + dev_dbg(&dev->dev, " io %#llx-%#llx flags %#lx\n", + (unsigned long long) res->start, + (unsigned long long) res->end, res->flags); + } + for (i = 0; i < PNP_MAX_MEM; i++) { + res = pnp_get_resource(dev, IORESOURCE_MEM, i); + if (res && !(res->flags & IORESOURCE_UNSET)) + dev_dbg(&dev->dev, " mem %#llx-%#llx flags %#lx\n", + (unsigned long long) res->start, + (unsigned long long) res->end, res->flags); + } +#endif +} diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index 55c4563986b3..9c2496dbeee4 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -56,14 +56,15 @@ static void reserve_range(struct pnp_dev *dev, resource_size_t start, static void reserve_resources_of_dev(struct pnp_dev *dev) { + struct resource *res; int i; - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_port_valid(dev, i)) + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { + if (res->flags & IORESOURCE_UNSET) continue; - if (pnp_port_start(dev, i) == 0) + if (res->start == 0) continue; /* disabled */ - if (pnp_port_start(dev, i) < 0x100) + if (res->start < 0x100) /* * Below 0x100 is only standard PC hardware * (pics, kbd, timer, dma, ...) @@ -73,19 +74,17 @@ static void reserve_resources_of_dev(struct pnp_dev *dev) * So, do nothing */ continue; - if (pnp_port_end(dev, i) < pnp_port_start(dev, i)) + if (res->end < res->start) continue; /* invalid */ - reserve_range(dev, pnp_port_start(dev, i), - pnp_port_end(dev, i), 1); + reserve_range(dev, res->start, res->end, 1); } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_mem_valid(dev, i)) + for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { + if (res->flags & IORESOURCE_UNSET) continue; - reserve_range(dev, pnp_mem_start(dev, i), - pnp_mem_end(dev, i), 0); + reserve_range(dev, res->start, res->end, 0); } } diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index bdb9b7285b3d..71be36f18709 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -262,7 +262,7 @@ static void ds2760_battery_work(struct work_struct *work) struct ds2760_device_info, monitor_work.work); const int interval = HZ * 60; - dev_dbg(di->dev, "%s\n", __FUNCTION__); + dev_dbg(di->dev, "%s\n", __func__); ds2760_battery_update_status(di); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); @@ -275,7 +275,7 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy) { struct ds2760_device_info *di = to_ds2760_device_info(psy); - dev_dbg(di->dev, "%s\n", __FUNCTION__); + dev_dbg(di->dev, "%s\n", __func__); cancel_delayed_work(&di->monitor_work); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index af7a231092a4..ab1e8289f07f 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -315,7 +315,6 @@ static int __init olpc_bat_init(void) if (ret) goto battery_failed; - olpc_register_battery_callback(&olpc_battery_trigger_uevent); goto success; battery_failed: @@ -328,7 +327,6 @@ success: static void __exit olpc_bat_exit(void) { - olpc_deregister_battery_callback(); power_supply_unregister(&olpc_bat); power_supply_unregister(&olpc_ac); platform_device_unregister(bat_pdev); diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 03d6a38464ef..138dd76ee347 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -39,7 +39,7 @@ static void power_supply_changed_work(struct work_struct *work) struct power_supply *psy = container_of(work, struct power_supply, changed_work); - dev_dbg(psy->dev, "%s\n", __FUNCTION__); + dev_dbg(psy->dev, "%s\n", __func__); class_for_each_device(power_supply_class, psy, __power_supply_changed_work); @@ -51,7 +51,7 @@ static void power_supply_changed_work(struct work_struct *work) void power_supply_changed(struct power_supply *psy) { - dev_dbg(psy->dev, "%s\n", __FUNCTION__); + dev_dbg(psy->dev, "%s\n", __func__); schedule_work(&psy->changed_work); } @@ -82,7 +82,7 @@ int power_supply_am_i_supplied(struct power_supply *psy) error = class_for_each_device(power_supply_class, psy, __power_supply_am_i_supplied); - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error); + dev_dbg(psy->dev, "%s %d\n", __func__, error); return error; } diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index fa3034f85c38..2dece40c544f 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -24,7 +24,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy) if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) return; - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval); + dev_dbg(psy->dev, "%s %d\n", __func__, status.intval); switch (status.intval) { case POWER_SUPPLY_STATUS_FULL: @@ -101,7 +101,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy) if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) return; - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval); + dev_dbg(psy->dev, "%s %d\n", __func__, online.intval); if (online.intval) led_trigger_event(psy->online_trig, LED_FULL); diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig index 4142115d298e..c32822ad84a4 100644 --- a/drivers/rapidio/Kconfig +++ b/drivers/rapidio/Kconfig @@ -1,14 +1,6 @@ # # RapidIO configuration # -config RAPIDIO_8_BIT_TRANSPORT - bool "8-bit transport addressing" - depends on RAPIDIO - ---help--- - By default, the kernel assumes a 16-bit addressed RapidIO - network. By selecting this option, the kernel will support - an 8-bit addressed network. - config RAPIDIO_DISC_TIMEOUT int "Discovery timeout duration (seconds)" depends on RAPIDIO diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c index 8b56bbdd011e..a3824baca2e5 100644 --- a/drivers/rapidio/rio-access.c +++ b/drivers/rapidio/rio-access.c @@ -48,7 +48,7 @@ int __rio_local_read_config_##size \ u32 data = 0; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->lcread(mport->id, offset, len, &data); \ + res = mport->ops->lcread(mport, mport->id, offset, len, &data); \ *value = (type)data; \ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ @@ -71,7 +71,7 @@ int __rio_local_write_config_##size \ unsigned long flags; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->lcwrite(mport->id, offset, len, value); \ + res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ } @@ -108,7 +108,7 @@ int rio_mport_read_config_##size \ u32 data = 0; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \ + res = mport->ops->cread(mport, mport->id, destid, hopcount, offset, len, &data); \ *value = (type)data; \ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ @@ -131,7 +131,7 @@ int rio_mport_write_config_##size \ unsigned long flags; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \ + res = mport->ops->cwrite(mport, mport->id, destid, hopcount, offset, len, value); \ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ } @@ -166,7 +166,7 @@ int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data) unsigned long flags; spin_lock_irqsave(&rio_doorbell_lock, flags); - res = mport->ops->dsend(mport->id, destid, data); + res = mport->ops->dsend(mport, mport->id, destid, data); spin_unlock_irqrestore(&rio_doorbell_lock, flags); return res; diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 44420723a359..a926c896475e 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -73,7 +73,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); - return RIO_GET_DID(result); + return RIO_GET_DID(port->sys_size, result); } /** @@ -88,7 +88,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) { rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, - RIO_SET_DID(did)); + RIO_SET_DID(port->sys_size, did)); } /** @@ -100,7 +100,8 @@ static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u */ static void rio_local_set_device_id(struct rio_mport *port, u16 did) { - rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(did)); + rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size, + did)); } /** @@ -350,8 +351,18 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rswitch->switchid = next_switchid; rswitch->hopcount = hopcount; rswitch->destid = destid; + rswitch->route_table = kzalloc(sizeof(u8)* + RIO_MAX_ROUTE_ENTRIES(port->sys_size), + GFP_KERNEL); + if (!rswitch->route_table) { + kfree(rdev); + rdev = NULL; + kfree(rswitch); + goto out; + } /* Initialize switch route table */ - for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++) + for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); + rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; rdev->rswitch = rswitch; sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id, @@ -480,7 +491,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) { u32 result; - rio_mport_read_config_32(port, RIO_ANY_DESTID, hopcount, + rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount, RIO_HOST_DID_LOCK_CSR, &result); return (u16) (result & 0xffff); @@ -571,14 +582,16 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, } /* Attempt to acquire device lock */ - rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, + rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), + hopcount, RIO_HOST_DID_LOCK_CSR, port->host_deviceid); while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) < port->host_deviceid) { /* Delay a bit */ mdelay(1); /* Attempt to acquire device lock again */ - rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, + rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), + hopcount, RIO_HOST_DID_LOCK_CSR, port->host_deviceid); } @@ -590,7 +603,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, } /* Setup new RIO device */ - if ((rdev = rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) { + rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size), + hopcount, 1); + if (rdev) { /* Add device to the global and bus/net specific list. */ list_add_tail(&rdev->net_list, &net->devices); } else @@ -598,7 +613,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, if (rio_is_switch(rdev)) { next_switchid++; - sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount); + sw_inport = rio_get_swpinfo_inport(port, + RIO_ANY_DESTID(port->sys_size), hopcount); rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport); rdev->rswitch->route_table[port->host_deviceid] = sw_inport; @@ -612,7 +628,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, } num_ports = - rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount); + rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size), + hopcount); pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", rio_name(rdev), rdev->vid, rdev->did, num_ports); @@ -624,13 +641,15 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, cur_destid = next_destid; if (rio_sport_is_active - (port, RIO_ANY_DESTID, hopcount, port_num)) { + (port, RIO_ANY_DESTID(port->sys_size), hopcount, + port_num)) { pr_debug( "RIO: scanning device on port %d\n", port_num); rio_route_add_entry(port, rdev->rswitch, - RIO_GLOBAL_TABLE, - RIO_ANY_DESTID, port_num); + RIO_GLOBAL_TABLE, + RIO_ANY_DESTID(port->sys_size), + port_num); if (rio_enum_peer(net, port, hopcount + 1) < 0) return -1; @@ -735,7 +754,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, pr_debug( "RIO: scanning device on port %d\n", port_num); - for (ndestid = 0; ndestid < RIO_ANY_DESTID; + for (ndestid = 0; + ndestid < RIO_ANY_DESTID(port->sys_size); ndestid++) { rio_route_get_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, @@ -917,7 +937,9 @@ static void rio_build_route_tables(void) list_for_each_entry(rdev, &rio_devices, global_list) if (rio_is_switch(rdev)) - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { + for (i = 0; + i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); + i++) { if (rio_route_get_entry (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, i, &sport) < 0) @@ -981,7 +1003,8 @@ int rio_disc_mport(struct rio_mport *mport) del_timer_sync(&rio_enum_timer); pr_debug("done\n"); - if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) { + if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), + 0) < 0) { printk(KERN_INFO "RIO: master port %d device has failed discovery\n", mport->id); diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 659e31164cf0..97a147f050d6 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -43,7 +43,8 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch if (!rdev->rswitch) goto out; - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); + i++) { if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE) continue; str += diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 80c5f1ba2e49..680661abbc4b 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -43,7 +43,7 @@ u16 rio_local_get_device_id(struct rio_mport *port) rio_local_read_config_32(port, RIO_DID_CSR, &result); - return (RIO_GET_DID(result)); + return (RIO_GET_DID(port->sys_size, result)); } /** diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index 80e3f03b5041..7786d02581f2 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -51,10 +51,5 @@ extern struct rio_route_ops __end_rio_route_ops[]; DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \ vid, did, add_hook, get_hook) -#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT -#define RIO_GET_DID(x) ((x & 0x00ff0000) >> 16) -#define RIO_SET_DID(x) ((x & 0x000000ff) << 16) -#else -#define RIO_GET_DID(x) (x & 0xffff) -#define RIO_SET_DID(x) (x & 0xffff) -#endif +#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16)) +#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16)) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 02a4c8cf2b2d..6cc2c0330230 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -20,10 +20,6 @@ menuconfig RTC_CLASS if RTC_CLASS -if GEN_RTC || RTC -comment "Conflicting RTC option has been selected, check GEN_RTC and RTC" -endif - config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" depends on RTC_CLASS = y @@ -304,6 +300,7 @@ comment "Platform RTC drivers" config RTC_DRV_CMOS tristate "PC-style 'CMOS'" depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS + default y if X86 help Say "yes" here to get direct support for the real time clock found in every PC or ACPI-based system, and some other boards. diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 52abffc86bcd..39e64ab1ecb7 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -83,7 +83,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = tm->tm_year - 1900; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -97,7 +97,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long cr; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -142,7 +142,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (at91_sys_read(AT91_RTC_IMR) & AT91_RTC_ALARM) ? 1 : 0; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -178,7 +178,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alrm->enabled) at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -193,7 +193,7 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, { int ret = 0; - pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg); + pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg); switch (cmd) { case RTC_AIE_OFF: /* alarm off */ @@ -265,7 +265,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__, + pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__, events >> 8, events & 0x000000FF); return IRQ_HANDLED; diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 56728a2a3385..38d8742a4bdf 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -288,7 +288,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) rtc_update_irq(rtc->rtcdev, 1, events); - pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__, + pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, events >> 8, events & 0x000000FF); return IRQ_HANDLED; diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 4f28045d9ef2..8624f55d0560 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -419,7 +419,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) return -ENOMEM; rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc))) { + if (IS_ERR(rtc)) { ret = PTR_ERR(rtc->rtc_dev); goto err; } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index dcdc142a3441..d060a06ce05b 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -854,11 +854,12 @@ cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) * don't define the IRQ. It should always be safe to * hardcode it in these cases */ - return cmos_do_probe(&pnp->dev, &pnp->res.port_resource[0], 8); + return cmos_do_probe(&pnp->dev, + pnp_get_resource(pnp, IORESOURCE_IO, 0), 8); else return cmos_do_probe(&pnp->dev, - &pnp->res.port_resource[0], - pnp->res.irq_resource[0].start); + pnp_get_resource(pnp, IORESOURCE_IO, 0), + pnp_irq(pnp, 0)); } static void __exit cmos_pnp_remove(struct pnp_dev *pnp) diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 7b002ceeaa7d..b9397818f73a 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -122,7 +122,7 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index f389a28720d2..bbf97e65202a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -99,45 +99,38 @@ struct ds1307 { }; struct chip_desc { - char name[9]; unsigned nvram56:1; unsigned alarm:1; - enum ds_type type; }; -static const struct chip_desc chips[] = { { - .name = "ds1307", - .type = ds_1307, +static const struct chip_desc chips[] = { +[ds_1307] = { .nvram56 = 1, -}, { - .name = "ds1337", - .type = ds_1337, +}, +[ds_1337] = { .alarm = 1, -}, { - .name = "ds1338", - .type = ds_1338, +}, +[ds_1338] = { .nvram56 = 1, -}, { - .name = "ds1339", - .type = ds_1339, +}, +[ds_1339] = { .alarm = 1, -}, { - .name = "ds1340", - .type = ds_1340, -}, { - .name = "m41t00", - .type = m41t00, +}, +[ds_1340] = { +}, +[m41t00] = { }, }; -static inline const struct chip_desc *find_chip(const char *s) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(chips); i++) - if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0) - return &chips[i]; - return NULL; -} +static const struct i2c_device_id ds1307_id[] = { + { "ds1307", ds_1307 }, + { "ds1337", ds_1337 }, + { "ds1338", ds_1338 }, + { "ds1339", ds_1339 }, + { "ds1340", ds_1340 }, + { "m41t00", m41t00 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1307_id); static int ds1307_get_time(struct device *dev, struct rtc_time *t) { @@ -326,21 +319,15 @@ static struct bin_attribute nvram = { static struct i2c_driver ds1307_driver; -static int __devinit ds1307_probe(struct i2c_client *client) +static int __devinit ds1307_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1307 *ds1307; int err = -ENODEV; int tmp; - const struct chip_desc *chip; + const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - chip = find_chip(client->name); - if (!chip) { - dev_err(&client->dev, "unknown chip type '%s'\n", - client->name); - return -ENODEV; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return -EIO; @@ -361,7 +348,7 @@ static int __devinit ds1307_probe(struct i2c_client *client) ds1307->msg[1].len = sizeof(ds1307->regs); ds1307->msg[1].buf = ds1307->regs; - ds1307->type = chip->type; + ds1307->type = id->driver_data; switch (ds1307->type) { case ds_1337: @@ -550,6 +537,7 @@ static struct i2c_driver ds1307_driver = { }, .probe = ds1307_probe, .remove = __devexit_p(ds1307_remove), + .id_table = ds1307_id, }; static int __init ds1307_init(void) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 45bda186befc..fa2d2f8b3f4d 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -41,6 +41,12 @@ #define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ #define DS1374_REG_TCR 0x09 /* Trickle Charge */ +static const struct i2c_device_id ds1374_id[] = { + { "rtc-ds1374", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1374_id); + struct ds1374 { struct i2c_client *client; struct rtc_device *rtc; @@ -355,7 +361,8 @@ static const struct rtc_class_ops ds1374_rtc_ops = { .ioctl = ds1374_ioctl, }; -static int ds1374_probe(struct i2c_client *client) +static int ds1374_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1374 *ds1374; int ret; @@ -429,6 +436,7 @@ static struct i2c_driver ds1374_driver = { }, .probe = ds1374_probe, .remove = __devexit_p(ds1374_remove), + .id_table = ds1374_id, }; static int __init ds1374_init(void) diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index d08912f18ddd..a83a40b3ebaa 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -181,8 +181,7 @@ ds1511_wdog_disable(void) * stupidly, some callers call with year unmolested; * and some call with year = year - 1900. thanks. */ - int -ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) +static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) { u8 mon, day, dow, hrs, min, sec, yrs, cen; unsigned int flags; @@ -245,8 +244,7 @@ ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) return 0; } - int -ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) +static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) { unsigned int century; unsigned int flags; diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index e0900ca678ec..6fa4556f5f5c 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -50,13 +50,13 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) /* read date registers */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } dev_dbg(&client->dev, "%s: raw read data - counters=%02x,%02x,%02x,%02x\n", - __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + __func__, buf[0], buf[1], buf[2], buf[3]); time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; @@ -64,7 +64,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); return 0; @@ -84,7 +84,7 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) xfer = i2c_master_send(client, buf, 6); if (xfer != 6) { - dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: send: %d\n", __func__, xfer); return -EIO; } @@ -98,7 +98,7 @@ static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -133,7 +133,7 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status) /* read control register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } @@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __func__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 725b0c73c333..fbb90b1e4098 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -15,16 +15,15 @@ #include <linux/bcd.h> #include <linux/rtc.h> -#define DRV_NAME "isl1208" -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3" /* Register map */ /* rtc section */ #define ISL1208_REG_SC 0x00 #define ISL1208_REG_MN 0x01 #define ISL1208_REG_HR 0x02 -#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ -#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ +#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ +#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ #define ISL1208_REG_DT 0x03 #define ISL1208_REG_MO 0x04 #define ISL1208_REG_YR 0x05 @@ -33,14 +32,14 @@ /* control/status section */ #define ISL1208_REG_SR 0x07 -#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ -#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ -#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ -#define ISL1208_REG_SR_ALM (1<<2) /* alarm */ -#define ISL1208_REG_SR_BAT (1<<1) /* battery */ -#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ +#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ +#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ +#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ +#define ISL1208_REG_SR_ALM (1<<2) /* alarm */ +#define ISL1208_REG_SR_BAT (1<<1) /* battery */ +#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ #define ISL1208_REG_INT 0x08 -#define ISL1208_REG_09 0x09 /* reserved */ +#define ISL1208_REG_09 0x09 /* reserved */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -58,39 +57,21 @@ #define ISL1208_REG_USR2 0x13 #define ISL1208_USR_SECTION_LEN 2 -/* i2c configuration */ -#define ISL1208_I2C_ADDR 0xde - -static const unsigned short normal_i2c[] = { - ISL1208_I2C_ADDR>>1, I2C_CLIENT_END -}; -I2C_CLIENT_INSMOD; /* defines addr_data */ - -static int isl1208_attach_adapter(struct i2c_adapter *adapter); -static int isl1208_detach_client(struct i2c_client *client); - -static struct i2c_driver isl1208_driver = { - .driver = { - .name = DRV_NAME, - }, - .id = I2C_DRIVERID_ISL1208, - .attach_adapter = &isl1208_attach_adapter, - .detach_client = &isl1208_detach_client, -}; +static struct i2c_driver isl1208_driver; /* block read */ static int isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], - unsigned len) + unsigned len) { u8 reg_addr[1] = { reg }; struct i2c_msg msgs[2] = { - { client->addr, client->flags, sizeof(reg_addr), reg_addr }, - { client->addr, client->flags | I2C_M_RD, len, buf } + {client->addr, 0, sizeof(reg_addr), reg_addr} + , + {client->addr, I2C_M_RD, len, buf} }; int ret; - BUG_ON(len == 0); BUG_ON(reg > ISL1208_REG_USR2); BUG_ON(reg + len > ISL1208_REG_USR2 + 1); @@ -103,15 +84,14 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], /* block write */ static int isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], - unsigned len) + unsigned len) { u8 i2c_buf[ISL1208_REG_USR2 + 2]; struct i2c_msg msgs[1] = { - { client->addr, client->flags, len + 1, i2c_buf } + {client->addr, 0, len + 1, i2c_buf} }; int ret; - BUG_ON(len == 0); BUG_ON(reg > ISL1208_REG_USR2); BUG_ON(reg + len > ISL1208_REG_USR2 + 1); @@ -125,7 +105,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], } /* simple check to see wether we have a isl1208 */ -static int isl1208_i2c_validate_client(struct i2c_client *client) +static int +isl1208_i2c_validate_client(struct i2c_client *client) { u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; u8 zero_mask[ISL1208_RTC_SECTION_LEN] = { @@ -139,24 +120,29 @@ static int isl1208_i2c_validate_client(struct i2c_client *client) return ret; for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) { - if (regs[i] & zero_mask[i]) /* check if bits are cleared */ + if (regs[i] & zero_mask[i]) /* check if bits are cleared */ return -ENODEV; } return 0; } -static int isl1208_i2c_get_sr(struct i2c_client *client) +static int +isl1208_i2c_get_sr(struct i2c_client *client) { - return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0; + int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR); + if (sr < 0) + return -EIO; + + return sr; } -static int isl1208_i2c_get_atr(struct i2c_client *client) +static int +isl1208_i2c_get_atr(struct i2c_client *client) { int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR); - if (atr < 0) - return -EIO; + return atr; /* The 6bit value in the ATR register controls the load * capacitance C_load * in steps of 0.25pF @@ -169,51 +155,54 @@ static int isl1208_i2c_get_atr(struct i2c_client *client) * */ - atr &= 0x3f; /* mask out lsb */ - atr ^= 1<<5; /* invert 6th bit */ - atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ + atr &= 0x3f; /* mask out lsb */ + atr ^= 1 << 5; /* invert 6th bit */ + atr += 2 * 9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ return atr; } -static int isl1208_i2c_get_dtr(struct i2c_client *client) +static int +isl1208_i2c_get_dtr(struct i2c_client *client) { int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR); - if (dtr < 0) return -EIO; /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ - dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1); + dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); return dtr; } -static int isl1208_i2c_get_usr(struct i2c_client *client) +static int +isl1208_i2c_get_usr(struct i2c_client *client) { u8 buf[ISL1208_USR_SECTION_LEN] = { 0, }; int ret; - ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf, - ISL1208_USR_SECTION_LEN); + ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1, buf, + ISL1208_USR_SECTION_LEN); if (ret < 0) return ret; return (buf[1] << 8) | buf[0]; } -static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) +static int +isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) { u8 buf[ISL1208_USR_SECTION_LEN]; buf[0] = usr & 0xff; buf[1] = (usr >> 8) & 0xff; - return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf, - ISL1208_USR_SECTION_LEN); + return isl1208_i2c_set_regs(client, ISL1208_REG_USR1, buf, + ISL1208_USR_SECTION_LEN); } -static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) +static int +isl1208_rtc_proc(struct device *dev, struct seq_file *seq) { struct i2c_client *const client = to_i2c_client(dev); int sr, dtr, atr, usr; @@ -230,20 +219,19 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) (sr & ISL1208_REG_SR_ALM) ? " ALM" : "", (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "", (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "", - (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", - sr); + (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", sr); seq_printf(seq, "batt_status\t: %s\n", (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); dtr = isl1208_i2c_get_dtr(client); - if (dtr >= 0 -1) + if (dtr >= 0 - 1) seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); atr = isl1208_i2c_get_atr(client); if (atr >= 0) seq_printf(seq, "analog_trim\t: %d.%.2d pF\n", - atr>>2, (atr&0x3)*25); + atr >> 2, (atr & 0x3) * 25); usr = isl1208_i2c_get_usr(client); if (usr >= 0) @@ -252,9 +240,8 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } - -static int isl1208_i2c_read_time(struct i2c_client *client, - struct rtc_time *tm) +static int +isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) { int sr; u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; @@ -274,27 +261,30 @@ static int isl1208_i2c_read_time(struct i2c_client *client, tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]); tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]); - { /* HR field has a more complex interpretation */ + + /* HR field has a more complex interpretation */ + { const u8 _hr = regs[ISL1208_REG_HR]; - if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ + if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ tm->tm_hour = BCD2BIN(_hr & 0x3f); - else { // 12h format + else { + /* 12h format */ tm->tm_hour = BCD2BIN(_hr & 0x1f); - if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ + if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ tm->tm_hour += 12; } } tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]); - tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ + tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100; tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]); return 0; } -static int isl1208_i2c_read_alarm(struct i2c_client *client, - struct rtc_wkalrm *alarm) +static int +isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; @@ -307,7 +297,7 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client, } sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs, - ISL1208_ALARM_SECTION_LEN); + ISL1208_ALARM_SECTION_LEN); if (sr < 0) { dev_err(&client->dev, "%s: reading alarm section failed\n", __func__); @@ -315,23 +305,25 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client, } /* MSB of each alarm register is an enable bit */ - tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f); - tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f); - tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f); - tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f); - tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1; - tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03); + tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f); + tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f); + tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f); + tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f); + tm->tm_mon = + BCD2BIN(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1; + tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03); return 0; } -static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int +isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) { return isl1208_i2c_read_time(to_i2c_client(dev), tm); } -static int isl1208_i2c_set_time(struct i2c_client *client, - struct rtc_time const *tm) +static int +isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) { int sr; u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; @@ -353,7 +345,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client, } /* set WRTC */ - sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr | ISL1208_REG_SR_WRTC); if (sr < 0) { dev_err(&client->dev, "%s: writing SR failed\n", __func__); @@ -369,7 +361,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client, } /* clear WRTC again */ - sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr & ~ISL1208_REG_SR_WRTC); if (sr < 0) { dev_err(&client->dev, "%s: writing SR failed\n", __func__); @@ -380,70 +372,69 @@ static int isl1208_i2c_set_time(struct i2c_client *client, } -static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int +isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) { return isl1208_i2c_set_time(to_i2c_client(dev), tm); } -static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +static int +isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); } static const struct rtc_class_ops isl1208_rtc_ops = { - .proc = isl1208_rtc_proc, - .read_time = isl1208_rtc_read_time, - .set_time = isl1208_rtc_set_time, - .read_alarm = isl1208_rtc_read_alarm, - //.set_alarm = isl1208_rtc_set_alarm, + .proc = isl1208_rtc_proc, + .read_time = isl1208_rtc_read_time, + .set_time = isl1208_rtc_set_time, + .read_alarm = isl1208_rtc_read_alarm, + /*.set_alarm = isl1208_rtc_set_alarm, */ }; /* sysfs interface */ -static ssize_t isl1208_sysfs_show_atrim(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t +isl1208_sysfs_show_atrim(struct device *dev, + struct device_attribute *attr, char *buf) { - int atr; - - atr = isl1208_i2c_get_atr(to_i2c_client(dev)); + int atr = isl1208_i2c_get_atr(to_i2c_client(dev)); if (atr < 0) return atr; - return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25); + return sprintf(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25); } + static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL); -static ssize_t isl1208_sysfs_show_dtrim(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t +isl1208_sysfs_show_dtrim(struct device *dev, + struct device_attribute *attr, char *buf) { - int dtr; - - dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); + int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); if (dtr < 0) return dtr; return sprintf(buf, "%d ppm\n", dtr); } + static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); -static ssize_t isl1208_sysfs_show_usr(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t +isl1208_sysfs_show_usr(struct device *dev, + struct device_attribute *attr, char *buf) { - int usr; - - usr = isl1208_i2c_get_usr(to_i2c_client(dev)); + int usr = isl1208_i2c_get_usr(to_i2c_client(dev)); if (usr < 0) return usr; return sprintf(buf, "0x%.4x\n", usr); } -static ssize_t isl1208_sysfs_store_usr(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t +isl1208_sysfs_store_usr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { int usr = -1; @@ -460,124 +451,123 @@ static ssize_t isl1208_sysfs_store_usr(struct device *dev, return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count; } + static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, isl1208_sysfs_store_usr); static int -isl1208_probe(struct i2c_adapter *adapter, int addr, int kind) +isl1208_sysfs_register(struct device *dev) { - int rc = 0; - struct i2c_client *new_client = NULL; - struct rtc_device *rtc = NULL; + int err; - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - rc = -ENODEV; - goto failout; + err = device_create_file(dev, &dev_attr_atrim); + if (err) + return err; + + err = device_create_file(dev, &dev_attr_dtrim); + if (err) { + device_remove_file(dev, &dev_attr_atrim); + return err; } - new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (new_client == NULL) { - rc = -ENOMEM; - goto failout; + err = device_create_file(dev, &dev_attr_usr); + if (err) { + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_dtrim); } - new_client->addr = addr; - new_client->adapter = adapter; - new_client->driver = &isl1208_driver; - new_client->flags = 0; - strcpy(new_client->name, DRV_NAME); + return 0; +} - if (kind < 0) { - rc = isl1208_i2c_validate_client(new_client); - if (rc < 0) - goto failout; - } +static int +isl1208_sysfs_unregister(struct device *dev) +{ + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_usr); + + return 0; +} + +static int +isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int rc = 0; + struct rtc_device *rtc; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - rc = i2c_attach_client(new_client); - if (rc < 0) - goto failout; + if (isl1208_i2c_validate_client(client) < 0) + return -ENODEV; - dev_info(&new_client->dev, + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); rtc = rtc_device_register(isl1208_driver.driver.name, - &new_client->dev, - &isl1208_rtc_ops, THIS_MODULE); + &client->dev, &isl1208_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); - if (IS_ERR(rtc)) { - rc = PTR_ERR(rtc); - goto failout_detach; - } - - i2c_set_clientdata(new_client, rtc); + i2c_set_clientdata(client, rtc); - rc = isl1208_i2c_get_sr(new_client); + rc = isl1208_i2c_get_sr(client); if (rc < 0) { - dev_err(&new_client->dev, "reading status failed\n"); - goto failout_unregister; + dev_err(&client->dev, "reading status failed\n"); + goto exit_unregister; } if (rc & ISL1208_REG_SR_RTCF) - dev_warn(&new_client->dev, "rtc power failure detected, " + dev_warn(&client->dev, "rtc power failure detected, " "please set clock.\n"); - rc = device_create_file(&new_client->dev, &dev_attr_atrim); - if (rc < 0) - goto failout_unregister; - rc = device_create_file(&new_client->dev, &dev_attr_dtrim); - if (rc < 0) - goto failout_atrim; - rc = device_create_file(&new_client->dev, &dev_attr_usr); - if (rc < 0) - goto failout_dtrim; + rc = isl1208_sysfs_register(&client->dev); + if (rc) + goto exit_unregister; return 0; - failout_dtrim: - device_remove_file(&new_client->dev, &dev_attr_dtrim); - failout_atrim: - device_remove_file(&new_client->dev, &dev_attr_atrim); - failout_unregister: +exit_unregister: rtc_device_unregister(rtc); - failout_detach: - i2c_detach_client(new_client); - failout: - kfree(new_client); - return rc; -} -static int -isl1208_attach_adapter (struct i2c_adapter *adapter) -{ - return i2c_probe(adapter, &addr_data, isl1208_probe); + return rc; } static int -isl1208_detach_client(struct i2c_client *client) +isl1208_remove(struct i2c_client *client) { - int rc; - struct rtc_device *const rtc = i2c_get_clientdata(client); + struct rtc_device *rtc = i2c_get_clientdata(client); - if (rtc) - rtc_device_unregister(rtc); /* do we need to kfree? */ - - rc = i2c_detach_client(client); - if (rc) - return rc; - - kfree(client); + isl1208_sysfs_unregister(&client->dev); + rtc_device_unregister(rtc); return 0; } -/* module management */ +static const struct i2c_device_id isl1208_id[] = { + { "isl1208", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl1208_id); + +static struct i2c_driver isl1208_driver = { + .driver = { + .name = "rtc-isl1208", + }, + .probe = isl1208_probe, + .remove = isl1208_remove, + .id_table = isl1208_id, +}; -static int __init isl1208_init(void) +static int __init +isl1208_init(void) { return i2c_add_driver(&isl1208_driver); } -static void __exit isl1208_exit(void) +static void __exit +isl1208_exit(void) { i2c_del_driver(&isl1208_driver); } diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 1cb33cac1237..316bfaa80872 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -60,48 +60,21 @@ #define DRV_VERSION "0.05" -struct m41t80_chip_info { - const char *name; - u8 features; -}; - -static const struct m41t80_chip_info m41t80_chip_info_tbl[] = { - { - .name = "m41t80", - .features = 0, - }, - { - .name = "m41t81", - .features = M41T80_FEATURE_HT, - }, - { - .name = "m41t81s", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41t82", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41t83", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st84", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st85", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st87", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, +static const struct i2c_device_id m41t80_id[] = { + { "m41t80", 0 }, + { "m41t81", M41T80_FEATURE_HT }, + { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { } }; +MODULE_DEVICE_TABLE(i2c, m41t80_id); struct m41t80_data { - const struct m41t80_chip_info *chip; + u8 features; struct rtc_device *rtc; }; @@ -208,7 +181,7 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) struct m41t80_data *clientdata = i2c_get_clientdata(client); u8 reg; - if (clientdata->chip->features & M41T80_FEATURE_BL) { + if (clientdata->features & M41T80_FEATURE_BL) { reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); seq_printf(seq, "battery\t\t: %s\n", (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); @@ -756,12 +729,12 @@ static struct notifier_block wdt_notifier = { * ***************************************************************************** */ -static int m41t80_probe(struct i2c_client *client) +static int m41t80_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int i, rc = 0; + int rc = 0; struct rtc_device *rtc = NULL; struct rtc_time tm; - const struct m41t80_chip_info *chip; struct m41t80_data *clientdata = NULL; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C @@ -773,19 +746,6 @@ static int m41t80_probe(struct i2c_client *client) dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - chip = NULL; - for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) { - if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) { - chip = &m41t80_chip_info_tbl[i]; - break; - } - } - if (!chip) { - dev_err(&client->dev, "%s is not supported\n", client->name); - rc = -ENODEV; - goto exit; - } - clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL); if (!clientdata) { rc = -ENOMEM; @@ -801,7 +761,7 @@ static int m41t80_probe(struct i2c_client *client) } clientdata->rtc = rtc; - clientdata->chip = chip; + clientdata->features = id->driver_data; i2c_set_clientdata(client, clientdata); /* Make sure HT (Halt Update) bit is cleared */ @@ -810,7 +770,7 @@ static int m41t80_probe(struct i2c_client *client) goto ht_err; if (rc & M41T80_ALHOUR_HT) { - if (chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { m41t80_get_datetime(client, &tm); dev_info(&client->dev, "HT bit was set!\n"); dev_info(&client->dev, @@ -842,7 +802,7 @@ static int m41t80_probe(struct i2c_client *client) goto exit; #ifdef CONFIG_RTC_DRV_M41T80_WDT - if (chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { rc = misc_register(&wdt_dev); if (rc) goto exit; @@ -878,7 +838,7 @@ static int m41t80_remove(struct i2c_client *client) struct rtc_device *rtc = clientdata->rtc; #ifdef CONFIG_RTC_DRV_M41T80_WDT - if (clientdata->chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { misc_deregister(&wdt_dev); unregister_reboot_notifier(&wdt_notifier); } @@ -896,6 +856,7 @@ static struct i2c_driver m41t80_driver = { }, .probe = m41t80_probe, .remove = m41t80_remove, + .id_table = m41t80_id, }; static int __init m41t80_rtc_init(void) diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index 7683412970c4..ded3c0abad83 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -98,7 +98,7 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (rc != ARRAY_SIZE(msgs)) { dev_err(&client->dev, "%s: register read failed\n", - __FUNCTION__); + __func__); return -EIO; } return 0; @@ -150,7 +150,7 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) write_failed: dev_err(&client->dev, "%s: register write failed\n", - __FUNCTION__); + __func__); return -EIO; } @@ -214,7 +214,7 @@ static int max6900_i2c_clear_write_protect(struct i2c_client *client) rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0); if (rc < 0) { dev_err(&client->dev, "%s: control register write failed\n", - __FUNCTION__); + __func__); return -EIO; } return 0; diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 1f956dc5d56e..12f0310ae89c 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -140,7 +140,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) dt->tm_year -= 1900; #ifdef MAX6902_DEBUG - printk("\n%s : Read RTC values\n",__FUNCTION__); + printk("\n%s : Read RTC values\n",__func__); printk("tm_hour: %i\n",dt->tm_hour); printk("tm_min : %i\n",dt->tm_min); printk("tm_sec : %i\n",dt->tm_sec); @@ -158,7 +158,7 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) dt->tm_year = dt->tm_year+1900; #ifdef MAX6902_DEBUG - printk("\n%s : Setting RTC values\n",__FUNCTION__); + printk("\n%s : Setting RTC values\n",__func__); printk("tm_sec : %i\n",dt->tm_sec); printk("tm_min : %i\n",dt->tm_min); printk("tm_hour: %i\n",dt->tm_hour); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index b3317fcc16c3..0fc4c3630780 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -18,17 +18,7 @@ #include <linux/bcd.h> #include <linux/rtc.h> -#define DRV_VERSION "0.4.2" - -/* Addresses to scan: none - * This chip cannot be reliably autodetected. An empty eeprom - * located at 0x51 will pass the validation routine due to - * the way the registers are implemented. - */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Module parameters */ -I2C_CLIENT_INSMOD; +#define DRV_VERSION "0.4.3" #define PCF8563_REG_ST1 0x00 /* status */ #define PCF8563_REG_ST2 0x01 @@ -53,8 +43,10 @@ I2C_CLIENT_INSMOD; #define PCF8563_SC_LV 0x80 /* low voltage */ #define PCF8563_MO_C 0x80 /* century */ +static struct i2c_driver pcf8563_driver; + struct pcf8563 { - struct i2c_client client; + struct rtc_device *rtc; /* * The meaning of MO_C bit varies by the chip type. * From PCF8563 datasheet: this bit is toggled when the years @@ -72,16 +64,13 @@ struct pcf8563 { int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ }; -static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind); -static int pcf8563_detach(struct i2c_client *client); - /* * In the routines that deal directly with the pcf8563 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. */ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); + struct pcf8563 *pcf8563 = i2c_get_clientdata(client); unsigned char buf[13] = { PCF8563_REG_ST1 }; struct i2c_msg msgs[] = { @@ -91,7 +80,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) /* read registers */ if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } @@ -102,7 +91,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __FUNCTION__, + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); @@ -123,7 +112,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -138,13 +127,13 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); + struct pcf8563 *pcf8563 = i2c_get_clientdata(client); int i, err; unsigned char buf[9]; dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -174,7 +163,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) if (err != sizeof(data)) { dev_err(&client->dev, "%s: err=%d addr=%02x, data=%02x\n", - __FUNCTION__, err, data[0], data[1]); + __func__, err, data[0], data[1]); return -EIO; } }; @@ -219,7 +208,7 @@ static int pcf8563_validate_client(struct i2c_client *client) if (xfer != ARRAY_SIZE(msgs)) { dev_err(&client->dev, "%s: could not read register 0x%02X\n", - __FUNCTION__, pattern[i].reg); + __func__, pattern[i].reg); return -EIO; } @@ -231,7 +220,7 @@ static int pcf8563_validate_client(struct i2c_client *client) dev_dbg(&client->dev, "%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, " "max=%d, value=%d, raw=0x%02X\n", - __FUNCTION__, i, pattern[i].reg, pattern[i].mask, + __func__, i, pattern[i].reg, pattern[i].mask, pattern[i].min, pattern[i].max, value, buf); @@ -257,100 +246,75 @@ static const struct rtc_class_ops pcf8563_rtc_ops = { .set_time = pcf8563_rtc_set_time, }; -static int pcf8563_attach(struct i2c_adapter *adapter) -{ - return i2c_probe(adapter, &addr_data, pcf8563_probe); -} - -static struct i2c_driver pcf8563_driver = { - .driver = { - .name = "pcf8563", - }, - .id = I2C_DRIVERID_PCF8563, - .attach_adapter = &pcf8563_attach, - .detach_client = &pcf8563_detach, -}; - -static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) +static int pcf8563_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf8563 *pcf8563; - struct i2c_client *client; - struct rtc_device *rtc; int err = 0; - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + dev_dbg(&client->dev, "%s\n", __func__); - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - err = -ENODEV; - goto exit; - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - client = &pcf8563->client; - client->addr = address; - client->driver = &pcf8563_driver; - client->adapter = adapter; - - strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE); + pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL); + if (!pcf8563) + return -ENOMEM; /* Verify the chip is really an PCF8563 */ - if (kind < 0) { - if (pcf8563_validate_client(client) < 0) { - err = -ENODEV; - goto exit_kfree; - } - } - - /* Inform the i2c layer */ - if ((err = i2c_attach_client(client))) + if (pcf8563_validate_client(client) < 0) { + err = -ENODEV; goto exit_kfree; + } dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev, - &pcf8563_rtc_ops, THIS_MODULE); + pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name, + &client->dev, &pcf8563_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); - goto exit_detach; + if (IS_ERR(pcf8563->rtc)) { + err = PTR_ERR(pcf8563->rtc); + goto exit_kfree; } - i2c_set_clientdata(client, rtc); + i2c_set_clientdata(client, pcf8563); return 0; -exit_detach: - i2c_detach_client(client); - exit_kfree: kfree(pcf8563); -exit: return err; } -static int pcf8563_detach(struct i2c_client *client) +static int pcf8563_remove(struct i2c_client *client) { - struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); - int err; - struct rtc_device *rtc = i2c_get_clientdata(client); + struct pcf8563 *pcf8563 = i2c_get_clientdata(client); - if (rtc) - rtc_device_unregister(rtc); - - if ((err = i2c_detach_client(client))) - return err; + if (pcf8563->rtc) + rtc_device_unregister(pcf8563->rtc); kfree(pcf8563); return 0; } +static const struct i2c_device_id pcf8563_id[] = { + { "pcf8563", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf8563_id); + +static struct i2c_driver pcf8563_driver = { + .driver = { + .name = "rtc-pcf8563", + }, + .probe = pcf8563_probe, + .remove = pcf8563_remove, + .id_table = pcf8563_id, +}; + static int __init pcf8563_init(void) { return i2c_add_driver(&pcf8563_driver); diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 8b3997007506..3d09d8f0b1f0 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -15,7 +15,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/mc146818rtc.h> +#include <linux/rtc.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 8d300e6d0d9e..0c6257a034ff 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -108,12 +108,10 @@ void rtc_proc_add_device(struct rtc_device *rtc) if (rtc->id == 0) { struct proc_dir_entry *ent; - ent = create_proc_entry("driver/rtc", 0, NULL); - if (ent) { - ent->proc_fops = &rtc_proc_fops; + ent = proc_create_data("driver/rtc", 0, NULL, + &rtc_proc_fops, rtc); + if (ent) ent->owner = rtc->owner; - ent->data = rtc; - } } } diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 664e89a817ed..1c14d4497c4d 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -228,7 +228,7 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) ndelay(700); /* CE:L */ if (cnt++ > 100) { - dev_err(dev, "%s: timeout error\n", __FUNCTION__); + dev_err(dev, "%s: timeout error\n", __func__); return -EIO; } } @@ -289,7 +289,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) ndelay(700); /* CE:L */ if (cnt++ > 100) { - dev_err(dev, "%s: timeout error\n", __FUNCTION__); + dev_err(dev, "%s: timeout error\n", __func__); return -EIO; } } diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 6b67b5097927..56caf6b2c3e5 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -69,6 +69,15 @@ enum rtc_type { rtc_rv5c387a, }; +static const struct i2c_device_id rs5c372_id[] = { + { "rs5c372a", rtc_rs5c372a }, + { "rs5c372b", rtc_rs5c372b }, + { "rv5c386", rtc_rv5c386 }, + { "rv5c387a", rtc_rv5c387a }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rs5c372_id); + /* REVISIT: this assumes that: * - we're in the 21st century, so it's safe to ignore the century * bit for rv5c38[67] (REG_MONTH bit 7); @@ -99,7 +108,7 @@ static int rs5c_get_regs(struct rs5c372 *rs5c) * least 80219 chips; this works around that bug. */ if ((i2c_transfer(client->adapter, msgs, 1)) != 1) { - pr_debug("%s: can't read registers\n", rs5c->rtc->name); + dev_warn(&client->dev, "can't read registers\n"); return -EIO; } @@ -166,7 +175,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -181,7 +190,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -195,7 +204,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[7] = BIN2BCD(tm->tm_year - 100); if ((i2c_master_send(client, buf, 8)) != 8) { - dev_err(&client->dev, "%s: write error\n", __FUNCTION__); + dev_err(&client->dev, "%s: write error\n", __func__); return -EIO; } @@ -220,7 +229,7 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) *osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; if (trim) { - dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, tmp); + dev_dbg(&client->dev, "%s: raw trim=%x\n", __func__, tmp); tmp &= RS5C372_TRIM_MASK; if (tmp & 0x3e) { int t = tmp & 0x3f; @@ -494,13 +503,14 @@ static void rs5c_sysfs_unregister(struct device *dev) static struct i2c_driver rs5c372_driver; -static int rs5c372_probe(struct i2c_client *client) +static int rs5c372_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err = 0; struct rs5c372 *rs5c372; struct rtc_time tm; - dev_dbg(&client->dev, "%s\n", __FUNCTION__); + dev_dbg(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { err = -ENODEV; @@ -512,29 +522,17 @@ static int rs5c372_probe(struct i2c_client *client) goto exit; } - /* we read registers 0x0f then 0x00-0x0f; skip the first one */ - rs5c372->regs=&rs5c372->buf[1]; - rs5c372->client = client; i2c_set_clientdata(client, rs5c372); + rs5c372->type = id->driver_data; + + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ + rs5c372->regs = &rs5c372->buf[1]; err = rs5c_get_regs(rs5c372); if (err < 0) goto exit_kfree; - if (strcmp(client->name, "rs5c372a") == 0) - rs5c372->type = rtc_rs5c372a; - else if (strcmp(client->name, "rs5c372b") == 0) - rs5c372->type = rtc_rs5c372b; - else if (strcmp(client->name, "rv5c386") == 0) - rs5c372->type = rtc_rv5c386; - else if (strcmp(client->name, "rv5c387a") == 0) - rs5c372->type = rtc_rv5c387a; - else { - rs5c372->type = rtc_rs5c372b; - dev_warn(&client->dev, "assuming rs5c372b\n"); - } - /* clock may be set for am/pm or 24 hr time */ switch (rs5c372->type) { case rtc_rs5c372a: @@ -651,6 +649,7 @@ static struct i2c_driver rs5c372_driver = { }, .probe = rs5c372_probe, .remove = rs5c372_remove, + .id_table = rs5c372_id, }; static __init int rs5c372_init(void) diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index e8abc90c32c5..29f47bacfc77 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -34,6 +34,12 @@ #define S35390A_FLAG_RESET 0x80 #define S35390A_FLAG_TEST 0x01 +static const struct i2c_device_id s35390a_id[] = { + { "s35390a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, s35390a_id); + struct s35390a { struct i2c_client *client[8]; struct rtc_device *rtc; @@ -195,7 +201,8 @@ static const struct rtc_class_ops s35390a_rtc_ops = { static struct i2c_driver s35390a_driver; -static int s35390a_probe(struct i2c_client *client) +static int s35390a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err; unsigned int i; @@ -296,6 +303,7 @@ static struct i2c_driver s35390a_driver = { }, .probe = s35390a_probe, .remove = s35390a_remove, + .id_table = s35390a_id, }; static int __init s35390a_rtc_init(void) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 9f4d5129a496..f26e0cad8f16 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -68,7 +68,7 @@ static void s3c_rtc_setaie(int to) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __FUNCTION__, to); + pr_debug("%s: aie=%d\n", __func__, to); tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; @@ -82,7 +82,7 @@ static void s3c_rtc_setpie(int to) { unsigned int tmp; - pr_debug("%s: pie=%d\n", __FUNCTION__, to); + pr_debug("%s: pie=%d\n", __func__, to); spin_lock_irq(&s3c_rtc_pie_lock); tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; @@ -457,7 +457,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) struct resource *res; int ret; - pr_debug("%s: probe=%p\n", __FUNCTION__, pdev); + pr_debug("%s: probe=%p\n", __func__, pdev); /* find the IRQs */ diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index c594b34c6767..110699bb4787 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -361,7 +361,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 4d27ccc4fc06..2531ce4c9db0 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -145,6 +145,8 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, unsigned long now, alarm; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); + char *buf_ptr; + int adjust = 0; /* Only request alarms that trigger in the future. Disable them * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. @@ -154,7 +156,15 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, return retval; rtc_tm_to_time(&alm.time, &now); - alarm = simple_strtoul(buf, NULL, 0); + buf_ptr = (char *)buf; + if (*buf_ptr == '+') { + buf_ptr++; + adjust = 1; + } + alarm = simple_strtoul(buf_ptr, NULL, 0); + if (adjust) { + alarm += now; + } if (alarm > now) { /* Avoid accidentally clobbering active alarms; we can't * entirely prevent that here, without even the minimal diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 254c9fce27da..bc930022004a 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -147,7 +147,7 @@ static int __devexit test_remove(struct platform_device *plat_dev) return 0; } -static struct platform_driver test_drv = { +static struct platform_driver test_driver = { .probe = test_probe, .remove = __devexit_p(test_remove), .driver = { @@ -160,7 +160,7 @@ static int __init test_init(void) { int err; - if ((err = platform_driver_register(&test_drv))) + if ((err = platform_driver_register(&test_driver))) return err; if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) { @@ -191,7 +191,7 @@ exit_free_test0: platform_device_put(test0); exit_driver_unregister: - platform_driver_unregister(&test_drv); + platform_driver_unregister(&test_driver); return err; } @@ -199,7 +199,7 @@ static void __exit test_exit(void) { platform_device_unregister(test0); platform_device_unregister(test1); - platform_driver_unregister(&test_drv); + platform_driver_unregister(&test_driver); } MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 24203a06051a..10025d840268 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -107,7 +107,7 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt) dt->tm_year = BCD2BIN(tmp)+100; #ifdef DEBUG - printk("\n%s : Read RTC values\n",__FUNCTION__); + printk("\n%s : Read RTC values\n",__func__); printk("tm_hour: %i\n",dt->tm_hour); printk("tm_min : %i\n",dt->tm_min); printk("tm_sec : %i\n",dt->tm_sec); @@ -126,7 +126,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) struct v3020 *chip = dev_get_drvdata(dev); #ifdef DEBUG - printk("\n%s : Setting RTC values\n",__FUNCTION__); + printk("\n%s : Setting RTC values\n",__func__); printk("tm_sec : %i\n",dt->tm_sec); printk("tm_min : %i\n",dt->tm_min); printk("tm_hour: %i\n",dt->tm_hour); diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index b90fb1866ce9..eaf55945f21b 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -22,20 +22,7 @@ #include <linux/rtc.h> #include <linux/delay.h> -#define DRV_VERSION "1.0.7" - -/* Addresses to scan: none. This chip is located at - * 0x6f and uses a two bytes register addressing. - * Two bytes need to be written to read a single register, - * while most other chips just require one and take the second - * one as the data to be written. To prevent corrupting - * unknown chips, the user must explicitly set the probe parameter. - */ - -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Insmod parameters */ -I2C_CLIENT_INSMOD; +#define DRV_VERSION "1.0.8" /* offsets into CCR area */ @@ -91,19 +78,7 @@ I2C_CLIENT_INSMOD; #define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ -/* Prototypes */ -static int x1205_attach(struct i2c_adapter *adapter); -static int x1205_detach(struct i2c_client *client); -static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); - -static struct i2c_driver x1205_driver = { - .driver = { - .name = "x1205", - }, - .id = I2C_DRIVERID_X1205, - .attach_adapter = &x1205_attach, - .detach_client = &x1205_detach, -}; +static struct i2c_driver x1205_driver; /* * In the routines that deal directly with the x1205 hardware, we use @@ -124,14 +99,14 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, /* read date registers */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } dev_dbg(&client->dev, "%s: raw read data - sec=%02x, min=%02x, hr=%02x, " "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", - __FUNCTION__, + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); @@ -146,7 +121,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -164,7 +139,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) /* read status register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } @@ -187,7 +162,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour); buf[CCR_SEC] = BIN2BCD(tm->tm_sec); @@ -200,7 +175,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, if (datetoo) { dev_dbg(&client->dev, "%s: mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); @@ -216,12 +191,12 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, /* this sequence is required to unlock the chip */ if ((xfer = i2c_master_send(client, wel, 3)) != 3) { - dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); return -EIO; } if ((xfer = i2c_master_send(client, rwel, 3)) != 3) { - dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); return -EIO; } @@ -233,7 +208,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, if (xfer != 3) { dev_err(&client->dev, "%s: xfer=%d addr=%02x, data=%02x\n", - __FUNCTION__, + __func__, xfer, rdata[1], rdata[2]); return -EIO; } @@ -241,7 +216,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, /* disable further writes */ if ((xfer = i2c_master_send(client, diswe, 3)) != 3) { - dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer); return -EIO; } @@ -274,11 +249,11 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim) /* read dtr register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } - dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr); + dev_dbg(&client->dev, "%s: raw dtr=%x\n", __func__, dtr); *trim = 0; @@ -306,11 +281,11 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) /* read atr register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } - dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr); + dev_dbg(&client->dev, "%s: raw atr=%x\n", __func__, atr); /* atr is a two's complement value on 6 bits, * perform sign extension. The formula is @@ -319,11 +294,11 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) if (atr & 0x20) atr |= 0xC0; - dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr); + dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __func__, atr, atr); *trim = (atr * 250) + 11000; - dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim); + dev_dbg(&client->dev, "%s: real=%d\n", __func__, *trim); return 0; } @@ -377,7 +352,7 @@ static int x1205_validate_client(struct i2c_client *client) if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { dev_err(&client->dev, "%s: could not read register %x\n", - __FUNCTION__, probe_zero_pattern[i]); + __func__, probe_zero_pattern[i]); return -EIO; } @@ -385,7 +360,7 @@ static int x1205_validate_client(struct i2c_client *client) if ((buf & probe_zero_pattern[i+1]) != 0) { dev_err(&client->dev, "%s: register=%02x, zero pattern=%d, value=%x\n", - __FUNCTION__, probe_zero_pattern[i], i, buf); + __func__, probe_zero_pattern[i], i, buf); return -ENODEV; } @@ -405,7 +380,7 @@ static int x1205_validate_client(struct i2c_client *client) if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { dev_err(&client->dev, "%s: could not read register %x\n", - __FUNCTION__, probe_limits_pattern[i].reg); + __func__, probe_limits_pattern[i].reg); return -EIO; } @@ -416,7 +391,7 @@ static int x1205_validate_client(struct i2c_client *client) value < probe_limits_pattern[i].min) { dev_dbg(&client->dev, "%s: register=%x, lim pattern=%d, value=%d\n", - __FUNCTION__, probe_limits_pattern[i].reg, + __func__, probe_limits_pattern[i].reg, i, value); return -ENODEV; @@ -497,58 +472,50 @@ static ssize_t x1205_sysfs_show_dtrim(struct device *dev, } static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL); -static int x1205_attach(struct i2c_adapter *adapter) +static int x1205_sysfs_register(struct device *dev) { - return i2c_probe(adapter, &addr_data, x1205_probe); + int err; + + err = device_create_file(dev, &dev_attr_atrim); + if (err) + return err; + + err = device_create_file(dev, &dev_attr_dtrim); + if (err) + device_remove_file(dev, &dev_attr_atrim); + + return err; } -static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) +static void x1205_sysfs_unregister(struct device *dev) +{ + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_dtrim); +} + + +static int x1205_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err = 0; unsigned char sr; - struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - err = -ENODEV; - goto exit; - } - - if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - /* I2C client */ - client->addr = address; - client->driver = &x1205_driver; - client->adapter = adapter; - - strlcpy(client->name, x1205_driver.driver.name, I2C_NAME_SIZE); + dev_dbg(&client->dev, "%s\n", __func__); - /* Verify the chip is really an X1205 */ - if (kind < 0) { - if (x1205_validate_client(client) < 0) { - err = -ENODEV; - goto exit_kfree; - } - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - /* Inform the i2c layer */ - if ((err = i2c_attach_client(client))) - goto exit_kfree; + if (x1205_validate_client(client) < 0) + return -ENODEV; dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); rtc = rtc_device_register(x1205_driver.driver.name, &client->dev, &x1205_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); - goto exit_detach; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); i2c_set_clientdata(client, rtc); @@ -565,45 +532,42 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) else dev_err(&client->dev, "couldn't read status\n"); - err = device_create_file(&client->dev, &dev_attr_atrim); - if (err) goto exit_devreg; - err = device_create_file(&client->dev, &dev_attr_dtrim); - if (err) goto exit_atrim; + err = x1205_sysfs_register(&client->dev); + if (err) + goto exit_devreg; return 0; -exit_atrim: - device_remove_file(&client->dev, &dev_attr_atrim); - exit_devreg: rtc_device_unregister(rtc); -exit_detach: - i2c_detach_client(client); - -exit_kfree: - kfree(client); - -exit: return err; } -static int x1205_detach(struct i2c_client *client) +static int x1205_remove(struct i2c_client *client) { - int err; struct rtc_device *rtc = i2c_get_clientdata(client); - if (rtc) - rtc_device_unregister(rtc); - - if ((err = i2c_detach_client(client))) - return err; - - kfree(client); - + rtc_device_unregister(rtc); + x1205_sysfs_unregister(&client->dev); return 0; } +static const struct i2c_device_id x1205_id[] = { + { "x1205", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, x1205_id); + +static struct i2c_driver x1205_driver = { + .driver = { + .name = "rtc-x1205", + }, + .probe = x1205_probe, + .remove = x1205_remove, + .id_table = x1205_id, +}; + static int __init x1205_init(void) { return i2c_add_driver(&x1205_driver); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 556063e8f7a9..03c0e40a92ff 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -157,6 +157,7 @@ static int dasd_devices_open(struct inode *inode, struct file *file) } static const struct file_operations dasd_devices_file_ops = { + .owner = THIS_MODULE, .open = dasd_devices_open, .read = seq_read, .llseek = seq_lseek, @@ -311,17 +312,16 @@ out_error: int dasd_proc_init(void) { - dasd_proc_root_entry = proc_mkdir("dasd", &proc_root); + dasd_proc_root_entry = proc_mkdir("dasd", NULL); if (!dasd_proc_root_entry) goto out_nodasd; dasd_proc_root_entry->owner = THIS_MODULE; - dasd_devices_entry = create_proc_entry("devices", - S_IFREG | S_IRUGO | S_IWUSR, - dasd_proc_root_entry); + dasd_devices_entry = proc_create("devices", + S_IFREG | S_IRUGO | S_IWUSR, + dasd_proc_root_entry, + &dasd_devices_file_ops); if (!dasd_devices_entry) goto out_nodevices; - dasd_devices_entry->proc_fops = &dasd_devices_file_ops; - dasd_devices_entry->owner = THIS_MODULE; dasd_statistics_entry = create_proc_entry("statistics", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); @@ -335,7 +335,7 @@ dasd_proc_init(void) out_nostatistics: remove_proc_entry("devices", dasd_proc_root_entry); out_nodevices: - remove_proc_entry("dasd", &proc_root); + remove_proc_entry("dasd", NULL); out_nodasd: return -ENOENT; } @@ -345,5 +345,5 @@ dasd_proc_exit(void) { remove_proc_entry("devices", dasd_proc_root_entry); remove_proc_entry("statistics", dasd_proc_root_entry); - remove_proc_entry("dasd", &proc_root); + remove_proc_entry("dasd", NULL); } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 04787eab1016..bb52d2fbac18 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -36,7 +36,7 @@ static int dcssblk_open(struct inode *inode, struct file *filp); static int dcssblk_release(struct inode *inode, struct file *filp); static int dcssblk_make_request(struct request_queue *q, struct bio *bio); static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, - unsigned long *data); + void **kaddr, unsigned long *pfn); static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; @@ -636,7 +636,7 @@ fail: static int dcssblk_direct_access (struct block_device *bdev, sector_t secnum, - unsigned long *data) + void **kaddr, unsigned long *pfn) { struct dcssblk_dev_info *dev_info; unsigned long pgoff; @@ -649,7 +649,9 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, pgoff = secnum / (PAGE_SIZE / 512); if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) return -ERANGE; - *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE); + *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE); + *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; + return 0; } diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 0e1f35c9ed9d..3e5653c92f4b 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 b8f35bc52b7b..9e784d5f7f57 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 e3b3d390b4a3..40b11521cd20 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 ed507594e62b..35707c04e613 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/tape_proc.c b/drivers/s390/char/tape_proc.c index c9b96d51b28f..e7c888c14e71 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -111,6 +111,7 @@ static int tape_proc_open(struct inode *inode, struct file *file) static const struct file_operations tape_proc_ops = { + .owner = THIS_MODULE, .open = tape_proc_open, .read = seq_read, .llseek = seq_lseek, @@ -124,14 +125,12 @@ void tape_proc_init(void) { tape_proc_devices = - create_proc_entry ("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, - &proc_root); + proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL, + &tape_proc_ops); if (tape_proc_devices == NULL) { PRINT_WARN("tape: Cannot register procfs entry tapedevices\n"); return; } - tape_proc_devices->proc_fops = &tape_proc_ops; - tape_proc_devices->owner = THIS_MODULE; } /* @@ -141,5 +140,5 @@ void tape_proc_cleanup(void) { if (tape_proc_devices != NULL) - remove_proc_entry ("tapedevices", &proc_root); + remove_proc_entry ("tapedevices", NULL); } diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 70b1980a08b6..c1f2adefad41 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/blacklist.c b/drivers/s390/cio/blacklist.c index e8597ec92247..40ef948fcb3a 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -374,13 +374,10 @@ cio_ignore_proc_init (void) { struct proc_dir_entry *entry; - entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, - &proc_root); + entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, + &cio_ignore_proc_fops); if (!entry) return -ENOENT; - - entry->proc_fops = &cio_ignore_proc_fops; - return 0; } diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index fe1ad1722158..26a930e832bd 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 23ffcc4768a7..08a578161306 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 08f2235c5a6f..3c75412904dc 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 f4c132ab39ed..2808b6833b9e 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 c1afab5f72d6..595e327d2f76 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 e0c7adb8958e..abfd601d237a 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 4b92c84fb438..99403b0a97a7 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 a1718a0aa539..f308ad55a6d5 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 10aa1e780801..445cf364e461 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -3632,7 +3632,7 @@ qdio_add_procfs_entry(void) { proc_perf_file_registration=0; qdio_perf_proc_file=create_proc_entry(QDIO_PERF, - S_IFREG|0444,&proc_root); + S_IFREG|0444,NULL); if (qdio_perf_proc_file) { qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read; } else proc_perf_file_registration=-1; @@ -3647,7 +3647,7 @@ static void qdio_remove_procfs_entry(void) { if (!proc_perf_file_registration) /* means if it went ok earlier */ - remove_proc_entry(QDIO_PERF,&proc_root); + remove_proc_entry(QDIO_PERF,NULL); } /** @@ -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 bbef3764fbf8..47a7e6200b26 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 76728ae4b843..8e7697305a4c 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 f51ed9972587..dd22f4b37037 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 8f876f6ab367..e4ba6a0372ac 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 66f4f12503c9..699ac11debd8 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 055f5c3e7b56..436bf1f6d4a6 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 3921d1631a78..86ec50ddae13 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 1be353593a59..9f143c83bba3 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 e1bfe56087d6..94a8ead64ed4 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 a4e758143665..235703414370 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 44d2ef906ac7..383f32c1d347 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/scsi/aha152x.c b/drivers/scsi/aha152x.c index a09b2d3fdf5a..f5215fd4b73d 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -994,13 +994,13 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete, SCpnt->SCp.sent_command = 0; if(SCpnt->SCp.phase & (resetting|check_condition)) { - if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) { + if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt)); return FAILED; } } else { SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); - if(SCpnt->host_scribble==0) { + if(!SCpnt->host_scribble) { printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt)); return FAILED; } @@ -1162,7 +1162,7 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt) } DO_LOCK(flags); - issued = remove_SC(&ISSUE_SC, SCpnt)==0; + issued = remove_SC(&ISSUE_SC, SCpnt) == NULL; disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt); DO_UNLOCK(flags); diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index 1ac119733bac..f220e5e436ab 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -50,7 +50,7 @@ aic7770_map_registers(struct ahc_softc *ahc, u_int port) /* * Lock out other contenders for our i/o space. */ - if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) + if (!request_region(port, AHC_EISA_IOSIZE, "aic7xxx")) return (ENOMEM); ahc->tag = BUS_SPACE_PIO; ahc->bsh.ioport = port; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 0d7628f1f1ef..00f5b9868574 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -352,7 +352,7 @@ ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, resource_size_t *base) *base = pci_resource_start(ahc->dev_softc, 0); if (*base == 0) return (ENOMEM); - if (request_region(*base, 256, "aic7xxx") == 0) + if (!request_region(*base, 256, "aic7xxx")) return (ENOMEM); return (0); } @@ -369,7 +369,7 @@ ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, start = pci_resource_start(ahc->dev_softc, 1); if (start != 0) { *bus_addr = start; - if (request_mem_region(start, 0x1000, "aic7xxx") == 0) + if (!request_mem_region(start, 0x1000, "aic7xxx")) error = ENOMEM; if (error == 0) { *maddr = ioremap_nocache(start, 256); diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 8939fbf102fc..0fb5bf4c43ac 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -164,7 +164,7 @@ static inline u32 dma_low(dma_addr_t addr) static u8 adpt_read_blink_led(adpt_hba* host) { - if(host->FwDebugBLEDflag_P != 0) { + if (host->FwDebugBLEDflag_P) { if( readb(host->FwDebugBLEDflag_P) == 0xbc ){ return readb(host->FwDebugBLEDvalue_P); } diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 2cd6b4959eb2..c33bcb284df7 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -1443,7 +1443,7 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt, current_SC->SCp.this_residual = current_SC->SCp.buffer->length; current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; } else { - current_SC->SCp.ptr = 0; + current_SC->SCp.ptr = NULL; current_SC->SCp.this_residual = 0; current_SC->SCp.buffer = NULL; current_SC->SCp.buffers_residual = 0; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 32553639aded..44d8d5163a1a 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -134,6 +134,7 @@ static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive) static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount) { + ide_hwif_t *hwif = drive->hwif; int count; char *buf; @@ -145,14 +146,12 @@ static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, local_irq_save(flags); buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_input_bytes(drive, - buf + pc->b_count, count); + hwif->input_data(drive, NULL, buf + pc->b_count, count); kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); local_irq_restore(flags); } else { buf = sg_virt(pc->sg); - drive->hwif->atapi_input_bytes(drive, - buf + pc->b_count, count); + hwif->input_data(drive, NULL, buf + pc->b_count, count); } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { @@ -165,13 +164,14 @@ static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bcount) { printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); } } static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount) { + ide_hwif_t *hwif = drive->hwif; int count; char *buf; @@ -183,14 +183,12 @@ static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, local_irq_save(flags); buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_output_bytes(drive, - buf + pc->b_count, count); + hwif->output_data(drive, NULL, buf + pc->b_count, count); kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); local_irq_restore(flags); } else { buf = sg_virt(pc->sg); - drive->hwif->atapi_output_bytes(drive, - buf + pc->b_count, count); + hwif->output_data(drive, NULL, buf + pc->b_count, count); } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { @@ -203,7 +201,7 @@ static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bcount) { printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); - ide_atapi_write_zeros(drive, bcount); + ide_pad_transfer(drive, 1, bcount); } } @@ -258,7 +256,8 @@ idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, WIN_IDLEIMMEDIATE, + hwif->io_ports.command_addr); rq->errors++; @@ -431,14 +430,15 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) idescsi_input_buffers(drive, pc, temp); else - drive->hwif->atapi_input_bytes(drive, pc->cur_pos, temp); + hwif->input_data(drive, NULL, + pc->cur_pos, temp); printk(KERN_ERR "ide-scsi: transferred" " %d of %d bytes\n", temp, bcount); } pc->xferred += temp; pc->cur_pos += temp; - ide_atapi_discard_data(drive, bcount - temp); + ide_pad_transfer(drive, 0, bcount - temp); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } @@ -452,15 +452,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) if (pc->sg) idescsi_input_buffers(drive, pc, bcount); else - hwif->atapi_input_bytes(drive, pc->cur_pos, - bcount); + hwif->input_data(drive, NULL, pc->cur_pos, bcount); } else { pc->flags |= PC_FLAG_WRITING; if (pc->sg) idescsi_output_buffers(drive, pc, bcount); else - hwif->atapi_output_bytes(drive, pc->cur_pos, - bcount); + hwif->output_data(drive, NULL, pc->cur_pos, bcount); } /* Update the current position */ pc->xferred += bcount; @@ -493,8 +491,10 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) BUG_ON(HWGROUP(drive)->handler != NULL); /* Set the interrupt routine */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); + /* Send the actual packet */ - drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12); + hwif->output_data(drive, NULL, scsi->pc->c, 12); + if (pc->flags & PC_FLAG_DMA_OK) { pc->flags |= PC_FLAG_DMA_IN_PROGRESS; hwif->dma_ops->dma_start(drive); @@ -574,7 +574,7 @@ static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive, return ide_started; } else { /* Issue the packet command */ - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); + ide_execute_pkt_cmd(drive); return idescsi_transfer_pc(drive); } } diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index b135a1ed4b2c..18551aaf5e09 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4996,7 +4996,7 @@ static int __init megaraid_init(void) max_mbox_busy_wait = MBOX_BUSY_WAIT; #ifdef CONFIG_PROC_FS - mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root); + mega_proc_dir_entry = proc_mkdir("megaraid", NULL); if (!mega_proc_dir_entry) { printk(KERN_WARNING "megaraid: failed to create megaraid root\n"); @@ -5005,7 +5005,7 @@ static int __init megaraid_init(void) error = pci_register_driver(&megaraid_pci_driver); if (error) { #ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", &proc_root); + remove_proc_entry("megaraid", NULL); #endif return error; } @@ -5035,7 +5035,7 @@ static void __exit megaraid_exit(void) pci_unregister_driver(&megaraid_pci_driver); #ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", &proc_root); + remove_proc_entry("megaraid", NULL); #endif } diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c index e55b9037adb2..1dd70d7a4947 100644 --- a/drivers/scsi/mvsas.c +++ b/drivers/scsi/mvsas.c @@ -2822,7 +2822,9 @@ static void mvs_update_phyinfo(struct mvs_info *mvi, int i, dev_printk(KERN_DEBUG, &pdev->dev, "phy[%d] Get Attached Address 0x%llX ," " SAS Address 0x%llX\n", - i, phy->att_dev_sas_addr, phy->dev_sas_addr); + i, + (unsigned long long)phy->att_dev_sas_addr, + (unsigned long long)phy->dev_sas_addr); dev_printk(KERN_DEBUG, &pdev->dev, "Rate = %x , type = %d\n", sas_phy->linkrate, phy->phy_type); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index d89289400425..c57c94c0ffd2 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -8186,7 +8186,7 @@ static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd) cmd->next_wcmd = NULL; if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; else { - while ((wcmd->next_wcmd) != 0) + while (wcmd->next_wcmd) wcmd = (struct scsi_cmnd *) wcmd->next_wcmd; wcmd->next_wcmd = (char *) cmd; } @@ -8222,7 +8222,7 @@ static void process_waiting_list(struct ncb *np, int sts) #ifdef DEBUG_WAITING_LIST if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); #endif - while ((wcmd = waiting_list) != 0) { + while ((wcmd = waiting_list) != NULL) { waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd; wcmd->next_wcmd = NULL; if (sts == DID_OK) { diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 07103c399fe0..f6600bfb5bde 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1773,7 +1773,7 @@ static int scsi_debug_slave_alloc(struct scsi_device *sdp) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags); + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); return 0; } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b8de041bc0ae..a235802f2981 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -449,37 +449,40 @@ int scsi_get_device_flags(struct scsi_device *sdev, } #ifdef CONFIG_SCSI_PROC_FS -/* - * proc_scsi_dev_info_read: dump the scsi_dev_info_list via - * /proc/scsi/device_info - */ -static int proc_scsi_devinfo_read(char *buffer, char **start, - off_t offset, int length) +static int devinfo_seq_show(struct seq_file *m, void *v) { - struct scsi_dev_info_list *devinfo; - int size, len = 0; - off_t begin = 0; - off_t pos = 0; + struct scsi_dev_info_list *devinfo = + list_entry(v, struct scsi_dev_info_list, dev_info_list); - list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) { - size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n", + seq_printf(m, "'%.8s' '%.16s' 0x%x\n", devinfo->vendor, devinfo->model, devinfo->flags); - len += size; - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } + return 0; +} + +static void * devinfo_seq_start(struct seq_file *m, loff_t *pos) +{ + return seq_list_start(&scsi_dev_info_list, *pos); +} -stop_output: - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - return (len); +static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + return seq_list_next(v, &scsi_dev_info_list, pos); +} + +static void devinfo_seq_stop(struct seq_file *m, void *v) +{ +} + +static const struct seq_operations scsi_devinfo_seq_ops = { + .start = devinfo_seq_start, + .next = devinfo_seq_next, + .stop = devinfo_seq_stop, + .show = devinfo_seq_show, +}; + +static int proc_scsi_devinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_devinfo_seq_ops); } /* @@ -489,11 +492,12 @@ stop_output: * integer value of flag to the scsi device info list. * To use, echo "vendor:model:flag" > /proc/scsi/device_info */ -static int proc_scsi_devinfo_write(struct file *file, const char __user *buf, - unsigned long length, void *data) +static ssize_t proc_scsi_devinfo_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) { char *buffer; - int err = length; + ssize_t err = length; if (!buf || length>PAGE_SIZE) return -EINVAL; @@ -517,6 +521,15 @@ out: free_page((unsigned long)buffer); return err; } + +static const struct file_operations scsi_devinfo_proc_fops = { + .owner = THIS_MODULE, + .open = proc_scsi_devinfo_open, + .read = seq_read, + .write = proc_scsi_devinfo_write, + .llseek = seq_lseek, + .release = seq_release, +}; #endif /* CONFIG_SCSI_PROC_FS */ module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); @@ -577,15 +590,13 @@ int __init scsi_init_devinfo(void) } #ifdef CONFIG_SCSI_PROC_FS - p = create_proc_entry("scsi/device_info", 0, NULL); + p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops); if (!p) { error = -ENOMEM; goto out; } p->owner = THIS_MODULE; - p->get_info = proc_scsi_devinfo_read; - p->write_proc = proc_scsi_devinfo_write; #endif /* CONFIG_SCSI_PROC_FS */ out: diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 334244c73955..eaf5a8add1ba 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1772,6 +1772,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag) unsigned long flags; int rtn; + blk_rq_init(NULL, &req); scmd->request = &req; memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout)); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba7e8ad76d04..a82d2fe80fb5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -536,6 +536,9 @@ static void scsi_run_queue(struct request_queue *q) !shost->host_blocked && !shost->host_self_blocked && !((shost->can_queue > 0) && (shost->host_busy >= shost->can_queue))) { + + int flagset; + /* * As long as shost is accepting commands and we have * starved queues, call blk_run_queue. scsi_request_fn @@ -549,19 +552,20 @@ static void scsi_run_queue(struct request_queue *q) sdev = list_entry(shost->starved_list.next, struct scsi_device, starved_entry); list_del_init(&sdev->starved_entry); - spin_unlock_irqrestore(shost->host_lock, flags); - + spin_unlock(shost->host_lock); + + spin_lock(sdev->request_queue->queue_lock); + flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && + !test_bit(QUEUE_FLAG_REENTER, + &sdev->request_queue->queue_flags); + if (flagset) + queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); + __blk_run_queue(sdev->request_queue); + if (flagset) + queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); + spin_unlock(sdev->request_queue->queue_lock); - if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_and_set_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags)) { - blk_run_queue(sdev->request_queue); - clear_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - } else - blk_run_queue(sdev->request_queue); - - spin_lock_irqsave(shost->host_lock, flags); + spin_lock(shost->host_lock); if (unlikely(!list_empty(&sdev->starved_entry))) /* * sdev lost a race, and was put back on the @@ -1586,8 +1590,9 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, blk_queue_max_segment_size(q, dma_get_max_seg_size(dev)); + /* New queue, no concurrency on queue_flags */ if (!shost->use_clustering) - clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); /* * set a reasonable default alignment on word boundaries: the diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 3a1c99d5c775..e4a0d2f9b357 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -413,6 +413,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file) } static const struct file_operations proc_scsi_operations = { + .owner = THIS_MODULE, .open = proc_scsi_open, .read = seq_read, .write = proc_scsi_write, @@ -431,10 +432,9 @@ int __init scsi_init_procfs(void) if (!proc_scsi) goto err1; - pde = create_proc_entry("scsi/scsi", 0, NULL); + pde = proc_create("scsi/scsi", 0, NULL, &proc_scsi_operations); if (!pde) goto err2; - pde->proc_fops = &proc_scsi_operations; return 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index fcd7455ffc39..a00eee6f7be9 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1828,7 +1828,7 @@ void scsi_scan_host(struct Scsi_Host *shost) } p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); - if (unlikely(IS_ERR(p))) + if (IS_ERR(p)) do_scan_async(data); } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 7899e3dda9bf..f4461d35ffb9 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -248,8 +248,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) else q->queuedata = shost; - set_bit(QUEUE_FLAG_BIDI, &q->queue_flags); - + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); return 0; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3cea17dd5dba..01cefbb2d539 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -860,7 +860,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp) static void sd_prepare_flush(struct request_queue *q, struct request *rq) { - memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2029422bc04d..c9d7f721b9e2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2667,7 +2667,6 @@ sg_proc_init(void) { int k, mask; int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - struct proc_dir_entry *pdep; struct sg_proc_leaf * leaf; sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL); @@ -2676,13 +2675,10 @@ sg_proc_init(void) for (k = 0; k < num_leaves; ++k) { leaf = &sg_proc_leaf_arr[k]; mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; - pdep = create_proc_entry(leaf->name, mask, sg_proc_sgp); - if (pdep) { - leaf->fops->owner = THIS_MODULE, - leaf->fops->read = seq_read, - leaf->fops->llseek = seq_lseek, - pdep->proc_fops = leaf->fops; - } + leaf->fops->owner = THIS_MODULE; + leaf->fops->read = seq_read; + leaf->fops->llseek = seq_lseek; + proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); } return 0; } diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 35142b5341b5..22a6aae78699 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -1647,7 +1647,7 @@ static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status) SYM_QUEHEAD *qp; struct sym_ccb *cp; - while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) { + while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) { struct scsi_cmnd *cmd; cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); @@ -3168,7 +3168,7 @@ int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int * the COMP queue and put back other ones into * the BUSY queue. */ - while ((qp = sym_remque_head(&qtmp)) != 0) { + while ((qp = sym_remque_head(&qtmp)) != NULL) { struct scsi_cmnd *cmd; cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); cmd = cp->cmd; @@ -5729,7 +5729,7 @@ void sym_hcb_free(struct sym_hcb *np) sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE"); if (np->actccbs) { - while ((qp = sym_remque_head(&np->free_ccbq)) != 0) { + while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) { cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); sym_mfree_dma(cp, sizeof(*cp), "CCB"); } diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index f385dce8dfbe..27aa40f3980e 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -951,7 +951,7 @@ static int ultrastor_abort(struct scsi_cmnd *SCpnt) printk("abort: command mismatch, %p != %p\n", config.mscp[mscp_index].SCint, SCpnt); #endif - if (config.mscp[mscp_index].SCint == 0) + if (config.mscp[mscp_index].SCint == NULL) return FAILED; if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); @@ -1101,7 +1101,7 @@ static void ultrastor_interrupt(void *dev_id) SCtmp = mscp->SCint; mscp->SCint = NULL; - if (SCtmp == 0) + if (!SCtmp) { #if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp); diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 2b8a410e0959..bbf5bc5892c7 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 2aa6bfe8fdb3..d9d4e9552a4d 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -51,6 +51,7 @@ extern int kgdb_output_string (const char* s, unsigned int count); /* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */ #include <linux/console.h> +#include <linux/jiffies.h> /* this defines the index into rs_table for the port to use */ @@ -994,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); @@ -1015,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; } @@ -1245,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)) @@ -1276,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) @@ -1435,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); @@ -1664,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; @@ -1716,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 @@ -1729,7 +1719,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && (time_after(jiffies, orig_jiffies + timeout))) break; /* The 'tx_cur' is really the next buffer to send. We * have to back up to the previous BD and wait for it @@ -1744,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.c b/drivers/serial/8250.c index 96a585e1cee8..a1ca9b7bf2d5 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1868,6 +1868,7 @@ static int serial8250_startup(struct uart_port *port) } if (is_real_interrupt(up->port.irq)) { + unsigned char iir1; /* * Test for UARTs that do not reassert THRE when the * transmitter is idle and the interrupt has already @@ -1881,7 +1882,7 @@ static int serial8250_startup(struct uart_port *port) wait_for_xmitr(up, UART_LSR_THRE); serial_out_sync(up, UART_IER, UART_IER_THRI); udelay(1); /* allow THRE to set */ - serial_in(up, UART_IIR); + iir1 = serial_in(up, UART_IIR); serial_out(up, UART_IER, 0); serial_out_sync(up, UART_IER, UART_IER_THRI); udelay(1); /* allow a working UART time to re-assert THRE */ @@ -1894,7 +1895,7 @@ static int serial8250_startup(struct uart_port *port) * If the interrupt is not reasserted, setup a timer to * kick the UART on a regular basis. */ - if (iir & UART_IIR_NO_INT) { + if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { pr_debug("ttyS%d - using backup timer\n", port->line); up->timer.function = serial8250_backup_timeout; up->timer.data = (unsigned long)up; @@ -2228,7 +2229,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); - tty_termios_encode_baud_rate(termios, baud, baud); + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); } static void @@ -2268,7 +2271,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) } if (up->port.flags & UPF_IOREMAP) { - up->port.membase = ioremap(up->port.mapbase, size); + up->port.membase = ioremap_nocache(up->port.mapbase, + size); if (!up->port.membase) { release_mem_region(up->port.mapbase, size); ret = -ENOMEM; diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c deleted file mode 100644 index 58015fd14be9..000000000000 --- a/drivers/serial/8250_au1x00.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Serial Device Initialisation for Au1x00 - * - * (C) Copyright Embedded Alley Solutions, Inc 2005 - * Author: Pantelis Antoniou <pantelis@embeddedalley.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/serial_core.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include <linux/serial_8250.h> - -#include <asm/mach-au1x00/au1000.h> - -#include "8250.h" - -#define PORT(_base, _irq) \ - { \ - .iobase = _base, \ - .membase = (void __iomem *)_base,\ - .mapbase = CPHYSADDR(_base), \ - .irq = _irq, \ - .uartclk = 0, /* filled */ \ - .regshift = 2, \ - .iotype = UPIO_AU, \ - .flags = UPF_SKIP_TEST \ - } - -static struct plat_serial8250_port au1x00_data[] = { -#if defined(CONFIG_SOC_AU1000) - PORT(UART0_ADDR, AU1000_UART0_INT), - PORT(UART1_ADDR, AU1000_UART1_INT), - PORT(UART2_ADDR, AU1000_UART2_INT), - PORT(UART3_ADDR, AU1000_UART3_INT), -#elif defined(CONFIG_SOC_AU1500) - PORT(UART0_ADDR, AU1500_UART0_INT), - PORT(UART3_ADDR, AU1500_UART3_INT), -#elif defined(CONFIG_SOC_AU1100) - PORT(UART0_ADDR, AU1100_UART0_INT), - PORT(UART1_ADDR, AU1100_UART1_INT), - /* The internal UART2 does not exist on the AU1100 processor. */ - PORT(UART3_ADDR, AU1100_UART3_INT), -#elif defined(CONFIG_SOC_AU1550) - PORT(UART0_ADDR, AU1550_UART0_INT), - PORT(UART1_ADDR, AU1550_UART1_INT), - PORT(UART3_ADDR, AU1550_UART3_INT), -#elif defined(CONFIG_SOC_AU1200) - PORT(UART0_ADDR, AU1200_UART0_INT), - PORT(UART1_ADDR, AU1200_UART1_INT), -#endif - { }, -}; - -static struct platform_device au1x00_device = { - .name = "serial8250", - .id = PLAT8250_DEV_AU1X00, - .dev = { - .platform_data = au1x00_data, - }, -}; - -static int __init au1x00_init(void) -{ - int i; - unsigned int uartclk; - - /* get uart clock */ - uartclk = get_au1x00_uart_baud_base() * 16; - - /* fill up uartclk */ - for (i = 0; au1x00_data[i].flags ; i++) - au1x00_data[i].uartclk = uartclk; - - return platform_device_register(&au1x00_device); -} - -/* XXX: Yes, I know this doesn't yet work. */ -static void __exit au1x00_exit(void) -{ - platform_device_unregister(&au1x00_device); -} - -module_init(au1x00_init); -module_exit(au1x00_exit); - -MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>"); -MODULE_DESCRIPTION("8250 serial probe module for Au1x000 cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index 38776e8b064b..f279745e9fef 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -153,10 +153,10 @@ static int __init parse_options(struct early_serial8250_device *device, (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); port->membase += port->mapbase & ~PAGE_MASK; #else - port->membase = ioremap(port->mapbase, 64); + port->membase = ioremap_nocache(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/8250_pci.c b/drivers/serial/8250_pci.c index f97224ce59da..53fa19cf2f06 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -86,7 +86,7 @@ setup_port(struct serial_private *priv, struct uart_port *port, len = pci_resource_len(dev, bar); if (!priv->remapped_bar[bar]) - priv->remapped_bar[bar] = ioremap(base, len); + priv->remapped_bar[bar] = ioremap_nocache(base, len); if (!priv->remapped_bar[bar]) return -ENOMEM; @@ -270,7 +270,7 @@ static int pci_plx9050_init(struct pci_dev *dev) /* * enable/disable interrupts */ - p = ioremap(pci_resource_start(dev, 0), 0x80); + p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); if (p == NULL) return -ENOMEM; writel(irq_config, p + 0x4c); @@ -294,7 +294,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev) /* * disable interrupts */ - p = ioremap(pci_resource_start(dev, 0), 0x80); + p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); if (p != NULL) { writel(0, p + 0x4c); @@ -341,7 +341,8 @@ static int sbs_init(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + p = ioremap_nocache(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); if (p == NULL) return -ENOMEM; @@ -365,7 +366,8 @@ static void __devexit sbs_exit(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + p = ioremap_nocache(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); /* FIXME: What if resource_len < OCT_REG_CR_OFF */ if (p != NULL) writeb(0, p + OCT_REG_CR_OFF); @@ -419,7 +421,7 @@ static int pci_siig10x_init(struct pci_dev *dev) break; } - p = ioremap(pci_resource_start(dev, 0), 0x80); + p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); if (p == NULL) return -ENOMEM; @@ -775,7 +777,7 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board, * This list is ordered alphabetically by vendor then device. * Specific entries must come before more generic entries. */ -static struct pci_serial_quirk pci_serial_quirks[] = { +static struct pci_serial_quirk pci_serial_quirks[] __refdata = { /* * ADDI-DATA GmbH communication cards <info@addi-data.com> */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index f7cd9504d811..36acbcca2d48 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -262,12 +262,12 @@ config SERIAL_8250_ACORN cards. If unsure, say N. config SERIAL_8250_AU1X00 - bool "AU1X00 serial port support" + bool "Au1x00 serial port support" depends on SERIAL_8250 != n && SOC_AU1X00 help - If you have an Au1x00 board and want to use the serial port, say Y - to this option. The driver can handle 1 or 2 serial ports. - If unsure, say N. + If you have an Au1x00 SOC based board and want to use the serial port, + say Y to this option. The driver can handle up to 4 serial ports, + depending on the SOC. If unsure, say N. config SERIAL_8250_RM9K bool "Support for MIPS RM9xxx integrated serial port" @@ -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 3cbea5494724..0d9c09b1e836 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o -obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o @@ -28,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/atmel_serial.c b/drivers/serial/atmel_serial.c index 55492fa095a2..c065a704a93a 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -96,7 +96,6 @@ /* PDC registers */ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) #define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 5f55534a290b..8a2f6a1baa74 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 000000000000..aca1240ad808 --- /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 000000000000..671d41cc1a3f --- /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 a638ba0679ac..a19dc7ef8861 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 383c4e660cd5..f9fa237aa949 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,6 +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; + + local_irq_save(flags); if (clear & TIOCM_RTS) e100_rts(info, 0); @@ -3601,6 +3604,8 @@ rs_tiocmset(struct tty_struct *tty, struct file *file, e100_ri_out(info, 1); if (set & TIOCM_CD) e100_cd_out(info, 1); + + local_irq_restore(flags); return 0; } @@ -3609,6 +3614,9 @@ 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); result = (!E100_RTS_GET(info) ? TIOCM_RTS : 0) @@ -3618,6 +3626,8 @@ rs_tiocmget(struct tty_struct *tty, struct file *file) | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); + local_irq_restore(flags); + #ifdef SERIAL_DEBUG_IO printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", info->line, result, result); @@ -3695,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 */ @@ -3801,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; @@ -3878,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 */ @@ -3894,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(); } /* @@ -4513,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/dz.c b/drivers/serial/dz.c index 116211fcd36f..0dddd68b20d2 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -819,7 +819,7 @@ static void dz_console_putchar(struct uart_port *uport, int ch) dz_out(dport, DZ_TCR, mask); iob(); udelay(2); - } while (loops--); + } while (--loops); if (loops) /* Cannot send otherwise. */ dz_out(dport, DZ_TDR, ch); diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 168073f12cec..4f1af71e9a1b 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 0c179384fb0c..49b8a82b7b9f 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/jsm/jsm.h b/drivers/serial/jsm/jsm.h index 12c934a1f274..8871aaa3dba6 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h @@ -373,6 +373,7 @@ struct neo_uart_struct { #define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator" #define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI" #define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator" +#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM" /* * Our Global Variables. diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c index 6767ee381cd1..338cf8a08b43 100644 --- a/drivers/serial/jsm/jsm_driver.c +++ b/drivers/serial/jsm/jsm_driver.c @@ -82,7 +82,10 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* store the info for the board we've found */ brd->boardnum = adapter_count++; brd->pci_dev = pdev; - brd->maxports = 2; + if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM) + brd->maxports = 4; + else + brd->maxports = 2; spin_lock_init(&brd->bd_lock); spin_lock_init(&brd->bd_intr_lock); @@ -208,6 +211,7 @@ static struct pci_device_id jsm_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 }, { 0, } }; MODULE_DEVICE_TABLE(pci, jsm_pci_tbl); diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index 9cf03327386a..eadc1ab6bbce 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 ddd3aa50d4ad..43af40d59b8a 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 d93b3578c5e2..7a3625f52a03 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 3123ffeac8ad..81ac9bb4f39b 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 4ffa2585429a..2b6a013639e6 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -1022,6 +1022,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, struct uart_port *port = &ourport->port; struct s3c2410_uartcfg *cfg; struct resource *res; + int ret; dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev); @@ -1064,9 +1065,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, port->mapbase = res->start; port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART); - port->irq = platform_get_irq(platdev, 0); - if (port->irq < 0) + ret = platform_get_irq(platdev, 0); + if (ret < 0) port->irq = 0; + else + port->irq = ret; ourport->clk = clk_get(&platdev->dev, "uart"); @@ -1093,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); @@ -1584,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 67b2338913c2..62b38582f5e9 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 a9ca03ead3e5..1e2b9d826f69 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -329,13 +329,15 @@ EXPORT_SYMBOL(uart_update_timeout); * If it's still invalid, we try 9600 baud. * * Update the @termios structure to reflect the baud rate - * we're actually going to be using. + * we're actually going to be using. Don't do this for the case + * where B0 is requested ("hang up"). */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try, baud, altbaud = 38400; + int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; if (flags == UPF_SPD_HI) @@ -360,8 +362,10 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, /* * Special case: B0 rate. */ - if (baud == 0) + if (baud == 0) { + hung_up = 1; baud = 9600; + } if (baud >= min && baud <= max) return baud; @@ -373,7 +377,9 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, termios->c_cflag &= ~CBAUD; if (old) { baud = tty_termios_baud_rate(old); - tty_termios_encode_baud_rate(termios, baud, baud); + if (!hung_up) + tty_termios_encode_baud_rate(termios, + baud, baud); old = NULL; continue; } @@ -382,7 +388,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * As a last resort, if the quotient is zero, * default to 9600 bps */ - tty_termios_encode_baud_rate(termios, 9600, 9600); + if (!hung_up) + tty_termios_encode_baud_rate(termios, 9600, 9600); } return 0; @@ -415,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) { @@ -447,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) @@ -521,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) @@ -611,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; @@ -630,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; @@ -907,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) @@ -1052,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, @@ -1062,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. @@ -1133,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; } @@ -1146,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 @@ -1158,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); @@ -1193,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 @@ -1309,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 @@ -1359,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(); } /* @@ -2072,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 c2ea5d4df44a..969106187718 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 41fc61264443..019da2e05f0b 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/sunzilog.c b/drivers/serial/sunzilog.c index 3271379a36db..90a20a152ebf 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1231,7 +1231,7 @@ static inline struct console *SUNZILOG_CONSOLE(void) #define SUNZILOG_CONSOLE() (NULL) #endif -static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) +static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) { int baud, brg; @@ -1305,7 +1305,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R7] = 0x7E; /* SDLC Flag */ up->curregs[R9] = NV; up->curregs[R7p] = 0x00; - sunzilog_init_kbdms(up, up->port.line); + sunzilog_init_kbdms(up); /* Only enable interrupts if an ISR handler available */ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) up->curregs[R9] |= MIE; diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index b565d5a37499..b51c24245be4 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 5e4310ccd591..01917c433f17 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/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 98ab649c1ff9..bb6ce6bba32f 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -1,7 +1,7 @@ /* * Driver for NEC VR4100 series Serial Interface Unit. * - * Copyright (C) 2004-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2004-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> * * Based on drivers/serial/8250.c, by Russell King. * @@ -840,6 +840,19 @@ static int __devinit siu_console_init(void) console_initcall(siu_console_init); +void __init vr41xx_siu_early_setup(struct uart_port *port) +{ + if (port->type == PORT_UNKNOWN) + return; + + siu_uart_ports[port->line].line = port->line; + siu_uart_ports[port->line].type = port->type; + siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; + siu_uart_ports[port->line].mapbase = port->mapbase; + siu_uart_ports[port->line].mapbase = port->mapbase; + siu_uart_ports[port->line].ops = &siu_uart_ops; +} + #define SERIAL_VR41XX_CONSOLE &siu_console #else #define SERIAL_VR41XX_CONSOLE NULL diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d8107890db15..fae9e8f3d092 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -5,11 +5,9 @@ # nobody's needed a slave side API yet. The master-role API is not # fully appropriate there, so it'd need some thought to do well. # -menu "SPI support" - depends on HAS_IOMEM - -config SPI +menuconfig SPI bool "SPI support" + depends on HAS_IOMEM help The "Serial Peripheral Interface" is a low level synchronous protocol. Chips that support SPI can have data transfer rates @@ -28,9 +26,11 @@ config SPI (half duplex), SSP, SSI, and PSP. This driver framework should work with most such devices and controllers. +if SPI + config SPI_DEBUG boolean "Debug support for SPI drivers" - depends on SPI && DEBUG_KERNEL + depends on DEBUG_KERNEL help Say "yes" to enable debug messaging (like dev_dbg and pr_debug), sysfs, and debugfs support in SPI controller and protocol drivers. @@ -245,5 +245,4 @@ config SPI_TLE62X0 # (slave support would go here) -endmenu # "SPI support" - +endif # SPI diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 1749a27be066..e81d59d78910 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); @@ -616,7 +627,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) return -ESHUTDOWN; list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!(xfer->tx_buf || xfer->rx_buf)) { + if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) { dev_dbg(&spi->dev, "missing rx or tx buf\n"); return -EINVAL; } diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c index 5f00bd6500ef..d9ae111c27ae 100644 --- a/drivers/spi/omap_uwire.c +++ b/drivers/spi/omap_uwire.c @@ -151,7 +151,7 @@ static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch) if (time_after(jiffies, max_jiffies)) { printk(KERN_ERR "%s: timeout. reg=%#06x " "mask=%#06x val=%#06x\n", - __FUNCTION__, w, mask, val); + __func__, w, mask, val); return -1; } c++; @@ -437,7 +437,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) } omap_uwire_configure_mode(spi->chip_select, flags); pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n", - __FUNCTION__, flags, + __func__, flags, clk_get_rate(uwire->ck) / 1000, rate / 1000); status = 0; diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 147e26a78d64..654bb58be630 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -67,8 +67,11 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) #define DEFINE_SSP_REG(reg, off) \ -static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \ -static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); } +static inline u32 read_##reg(void const __iomem *p) \ +{ return __raw_readl(p + (off)); } \ +\ +static inline void write_##reg(u32 v, void __iomem *p) \ +{ __raw_writel(v, p + (off)); } DEFINE_SSP_REG(SSCR0, 0x00) DEFINE_SSP_REG(SSCR1, 0x04) @@ -106,7 +109,7 @@ struct driver_data { u32 *null_dma_buf; /* SSP register addresses */ - void *ioaddr; + void __iomem *ioaddr; u32 ssdr_physical; /* SSP masks*/ @@ -173,7 +176,7 @@ static int flush(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; do { while (read_SSSR(reg) & SSSR_RNE) { @@ -191,7 +194,7 @@ static void null_cs_control(u32 command) static int null_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) @@ -206,7 +209,7 @@ static int null_writer(struct driver_data *drv_data) static int null_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; while ((read_SSSR(reg) & SSSR_RNE) @@ -220,7 +223,7 @@ static int null_reader(struct driver_data *drv_data) static int u8_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) @@ -234,7 +237,7 @@ static int u8_writer(struct driver_data *drv_data) static int u8_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { @@ -247,7 +250,7 @@ static int u8_reader(struct driver_data *drv_data) static int u16_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) @@ -261,7 +264,7 @@ static int u16_writer(struct driver_data *drv_data) static int u16_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { @@ -274,7 +277,7 @@ static int u16_reader(struct driver_data *drv_data) static int u32_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) @@ -288,7 +291,7 @@ static int u32_writer(struct driver_data *drv_data) static int u32_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { @@ -412,7 +415,7 @@ static void giveback(struct driver_data *drv_data) msg->complete(msg->context); } -static int wait_ssp_rx_stall(void *ioaddr) +static int wait_ssp_rx_stall(void const __iomem *ioaddr) { unsigned long limit = loops_per_jiffy << 1; @@ -432,9 +435,9 @@ static int wait_dma_channel_stop(int channel) return limit; } -void dma_error_stop(struct driver_data *drv_data, const char *msg) +static void dma_error_stop(struct driver_data *drv_data, const char *msg) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; /* Stop and reset */ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; @@ -456,7 +459,7 @@ void dma_error_stop(struct driver_data *drv_data, const char *msg) static void dma_transfer_complete(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; struct spi_message *msg = drv_data->cur_msg; /* Clear and disable interrupts on SSP and DMA channels*/ @@ -536,7 +539,7 @@ static void dma_handler(int channel, void *data) static irqreturn_t dma_transfer(struct driver_data *drv_data) { u32 irq_status; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; irq_status = read_SSSR(reg) & drv_data->mask_sr; if (irq_status & SSSR_ROR) { @@ -570,7 +573,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) static void int_error_stop(struct driver_data *drv_data, const char* msg) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; /* Stop and reset SSP */ write_SSSR(drv_data->clear_sr, reg); @@ -588,7 +591,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) static void int_transfer_complete(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; /* Stop SSP */ write_SSSR(drv_data->clear_sr, reg); @@ -614,7 +617,7 @@ static void int_transfer_complete(struct driver_data *drv_data) static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ? drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; @@ -675,7 +678,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (!drv_data->cur_msg) { @@ -695,7 +698,8 @@ static irqreturn_t ssp_int(int irq, void *dev_id) return drv_data->transfer_handler(drv_data); } -int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi, +static int set_dma_burst_and_threshold(struct chip_data *chip, + struct spi_device *spi, u8 bits_per_word, u32 *burst_code, u32 *threshold) { @@ -809,7 +813,7 @@ static void pump_transfers(unsigned long data) struct spi_transfer *previous = NULL; struct chip_data *chip = NULL; struct ssp_device *ssp = drv_data->ssp; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u32 clk_div = 0; u8 bits = 0; u32 speed = 0; @@ -1338,7 +1342,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pxa2xx_spi_master *platform_info; struct spi_master *master; - struct driver_data *drv_data = 0; + struct driver_data *drv_data = NULL; struct ssp_device *ssp; int status = 0; diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index a9ac1fdb3094..7fea3cf4588a 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -608,6 +608,7 @@ static void pump_transfers(unsigned long data) u8 width; u16 cr, dma_width, dma_config; u32 tranf_success = 1; + u8 full_duplex = 0; /* Get current state information */ message = drv_data->cur_msg; @@ -658,6 +659,7 @@ static void pump_transfers(unsigned long data) } if (transfer->rx_buf != NULL) { + full_duplex = transfer->tx_buf != NULL; drv_data->rx = transfer->rx_buf; drv_data->rx_end = drv_data->rx + transfer->len; dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n", @@ -740,7 +742,8 @@ static void pump_transfers(unsigned long data) * successful use different way to r/w according to * drv_data->cur_chip->enable_dma */ - if (drv_data->cur_chip->enable_dma && drv_data->len > 6) { + if (!full_duplex && drv_data->cur_chip->enable_dma + && drv_data->len > 6) { disable_dma(drv_data->dma_channel); clear_dma_irqstat(drv_data->dma_channel); @@ -828,7 +831,7 @@ static void pump_transfers(unsigned long data) /* IO mode write then read */ dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); - if (drv_data->tx != NULL && drv_data->rx != NULL) { + if (full_duplex) { /* full duplex mode */ BUG_ON((drv_data->tx_end - drv_data->tx) != (drv_data->rx_end - drv_data->rx)); diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 71e881419cdd..96cc39ecb6e2 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -214,7 +214,7 @@ int spi_bitbang_setup(struct spi_device *spi) return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), + __func__, spi->mode & (SPI_CPOL | SPI_CPHA), spi->bits_per_word, 2 * cs->nsecs); /* NOTE we _need_ to call chipselect() early, ideally with adapter diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index d4ba640366b6..c730d05bfeb6 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -270,19 +270,26 @@ struct chip_data { static void pump_messages(struct work_struct *work); -static int flush(struct driver_data *drv_data) +static void flush(struct driver_data *drv_data) { - unsigned long limit = loops_per_jiffy << 1; void __iomem *regs = drv_data->regs; - volatile u32 d; + u32 control; dev_dbg(&drv_data->pdev->dev, "flush\n"); + + /* Wait for end of transaction */ do { - while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR) - d = readl(regs + SPI_RXDATA); - } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--); + control = readl(regs + SPI_CONTROL); + } while (control & SPI_CONTROL_XCH); + + /* Release chip select if requested, transfer delays are + handled in pump_transfers */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); - return limit; + /* Disable SPI to flush FIFOs */ + writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL); + writel(control, regs + SPI_CONTROL); } static void restore_state(struct driver_data *drv_data) @@ -570,6 +577,7 @@ static void giveback(struct spi_message *message, struct driver_data *drv_data) writel(0, regs + SPI_INT_STATUS); writel(0, regs + SPI_DMA); + /* Unconditioned deselct */ drv_data->cs_control(SPI_CS_DEASSERT); message->state = NULL; @@ -592,13 +600,10 @@ static void dma_err_handler(int channel, void *data, int errcode) /* Disable both rx and tx dma channels */ imx_dma_disable(drv_data->rx_channel); imx_dma_disable(drv_data->tx_channel); - - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_err_handler - flush failed\n"); - unmap_dma_buffers(drv_data); + flush(drv_data); + msg->state = ERROR_STATE; tasklet_schedule(&drv_data->pump_transfers); } @@ -612,8 +617,7 @@ static void dma_tx_handler(int channel, void *data) imx_dma_disable(channel); /* Now waits for TX FIFO empty */ - writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE, - drv_data->regs + SPI_INT_STATUS); + writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS); } static irqreturn_t dma_transfer(struct driver_data *drv_data) @@ -621,19 +625,18 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) u32 status; struct spi_message *msg = drv_data->cur_msg; void __iomem *regs = drv_data->regs; - unsigned long limit; status = readl(regs + SPI_INT_STATUS); - if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) { + if ((status & (SPI_INTEN_RO | SPI_STATUS_RO)) + == (SPI_INTEN_RO | SPI_STATUS_RO)) { writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); + imx_dma_disable(drv_data->tx_channel); imx_dma_disable(drv_data->rx_channel); unmap_dma_buffers(drv_data); - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer - flush failed\n"); + flush(drv_data); dev_warn(&drv_data->pdev->dev, "dma_transfer - fifo overun\n"); @@ -649,20 +652,17 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) if (drv_data->rx) { /* Wait end of transfer before read trailing data */ - limit = loops_per_jiffy << 1; - while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && - limit--); - - if (limit == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer - end of tx failed\n"); - else - dev_dbg(&drv_data->pdev->dev, - "dma_transfer - end of tx\n"); + while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) + cpu_relax(); imx_dma_disable(drv_data->rx_channel); unmap_dma_buffers(drv_data); + /* Release chip select if requested, transfer delays are + handled in pump_transfers() */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); + /* Calculate number of trailing data and read them */ dev_dbg(&drv_data->pdev->dev, "dma_transfer - test = 0x%08X\n", @@ -676,19 +676,12 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) /* Write only transfer */ unmap_dma_buffers(drv_data); - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer - flush failed\n"); + flush(drv_data); } /* End of transfer, update total byte transfered */ msg->actual_length += drv_data->len; - /* Release chip select if requested, transfer delays are - handled in pump_transfers() */ - if (drv_data->cs_change) - drv_data->cs_control(SPI_CS_DEASSERT); - /* Move to next transfer */ msg->state = next_transfer(drv_data); @@ -711,44 +704,43 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data) status = readl(regs + SPI_INT_STATUS); - while (status & SPI_STATUS_TH) { + if (status & SPI_INTEN_TE) { + /* TXFIFO Empty Interrupt on the last transfered word */ + writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); dev_dbg(&drv_data->pdev->dev, - "interrupt_wronly_transfer - status = 0x%08X\n", status); + "interrupt_wronly_transfer - end of tx\n"); - /* Pump data */ - if (write(drv_data)) { - writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, - regs + SPI_INT_STATUS); + flush(drv_data); - dev_dbg(&drv_data->pdev->dev, - "interrupt_wronly_transfer - end of tx\n"); + /* Update total byte transfered */ + msg->actual_length += drv_data->len; - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "interrupt_wronly_transfer - " - "flush failed\n"); + /* Move to next transfer */ + msg->state = next_transfer(drv_data); - /* End of transfer, update total byte transfered */ - msg->actual_length += drv_data->len; + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); - /* Release chip select if requested, transfer delays are - handled in pump_transfers */ - if (drv_data->cs_change) - drv_data->cs_control(SPI_CS_DEASSERT); + return IRQ_HANDLED; + } else { + while (status & SPI_STATUS_TH) { + dev_dbg(&drv_data->pdev->dev, + "interrupt_wronly_transfer - status = 0x%08X\n", + status); - /* Move to next transfer */ - msg->state = next_transfer(drv_data); + /* Pump data */ + if (write(drv_data)) { + /* End of TXFIFO writes, + now wait until TXFIFO is empty */ + writel(SPI_INTEN_TE, regs + SPI_INT_STATUS); + return IRQ_HANDLED; + } - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + status = readl(regs + SPI_INT_STATUS); - return IRQ_HANDLED; + /* We did something */ + handled = IRQ_HANDLED; } - - status = readl(regs + SPI_INT_STATUS); - - /* We did something */ - handled = IRQ_HANDLED; } return handled; @@ -758,45 +750,31 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; void __iomem *regs = drv_data->regs; - u32 status; + u32 status, control; irqreturn_t handled = IRQ_NONE; unsigned long limit; status = readl(regs + SPI_INT_STATUS); - while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) { + if (status & SPI_INTEN_TE) { + /* TXFIFO Empty Interrupt on the last transfered word */ + writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); dev_dbg(&drv_data->pdev->dev, - "interrupt_transfer - status = 0x%08X\n", status); - - if (status & SPI_STATUS_RO) { - writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, - regs + SPI_INT_STATUS); - - dev_warn(&drv_data->pdev->dev, - "interrupt_transfer - fifo overun\n" - " data not yet written = %d\n" - " data not yet read = %d\n", - data_to_write(drv_data), - data_to_read(drv_data)); - - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "interrupt_transfer - flush failed\n"); - - msg->state = ERROR_STATE; - tasklet_schedule(&drv_data->pump_transfers); + "interrupt_transfer - end of tx\n"); - return IRQ_HANDLED; - } - - /* Pump data */ - read(drv_data); - if (write(drv_data)) { - writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, - regs + SPI_INT_STATUS); + if (msg->state == ERROR_STATE) { + /* RXFIFO overrun was detected and message aborted */ + flush(drv_data); + } else { + /* Wait for end of transaction */ + do { + control = readl(regs + SPI_CONTROL); + } while (control & SPI_CONTROL_XCH); - dev_dbg(&drv_data->pdev->dev, - "interrupt_transfer - end of tx\n"); + /* Release chip select if requested, transfer delays are + handled in pump_transfers */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); /* Read trailing bytes */ limit = loops_per_jiffy << 1; @@ -810,27 +788,54 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) dev_dbg(&drv_data->pdev->dev, "interrupt_transfer - end of rx\n"); - /* End of transfer, update total byte transfered */ + /* Update total byte transfered */ msg->actual_length += drv_data->len; - /* Release chip select if requested, transfer delays are - handled in pump_transfers */ - if (drv_data->cs_change) - drv_data->cs_control(SPI_CS_DEASSERT); - /* Move to next transfer */ msg->state = next_transfer(drv_data); + } - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); - return IRQ_HANDLED; - } + return IRQ_HANDLED; + } else { + while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) { + dev_dbg(&drv_data->pdev->dev, + "interrupt_transfer - status = 0x%08X\n", + status); + + if (status & SPI_STATUS_RO) { + /* RXFIFO overrun, abort message end wait + until TXFIFO is empty */ + writel(SPI_INTEN_TE, regs + SPI_INT_STATUS); + + dev_warn(&drv_data->pdev->dev, + "interrupt_transfer - fifo overun\n" + " data not yet written = %d\n" + " data not yet read = %d\n", + data_to_write(drv_data), + data_to_read(drv_data)); + + msg->state = ERROR_STATE; + + return IRQ_HANDLED; + } - status = readl(regs + SPI_INT_STATUS); + /* Pump data */ + read(drv_data); + if (write(drv_data)) { + /* End of TXFIFO writes, + now wait until TXFIFO is empty */ + writel(SPI_INTEN_TE, regs + SPI_INT_STATUS); + return IRQ_HANDLED; + } - /* We did something */ - handled = IRQ_HANDLED; + status = readl(regs + SPI_INT_STATUS); + + /* We did something */ + handled = IRQ_HANDLED; + } } return handled; diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index be15a6213205..189f706b9e4b 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c @@ -310,7 +310,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi) return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", - __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), + __func__, spi->mode & (SPI_CPOL | SPI_CPHA), spi->bits_per_word, 2 * mpc83xx_spi->nsecs); /* NOTE we _need_ to call chipselect() early, ideally with adapter diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index b7476b888197..0885cc357a37 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -125,10 +125,10 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi, /* is clk = pclk / (2 * (pre+1)), or is it * clk = (pclk * 2) / ( pre + 1) */ - div = (div / 2) - 1; + div /= 2; - if (div < 0) - div = 1; + if (div > 0) + div -= 1; if (div > 255) div = 255; @@ -169,7 +169,7 @@ static int s3c24xx_spi_setup(struct spi_device *spi) } dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", - __FUNCTION__, spi->mode, spi->bits_per_word, + __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); return 0; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index cf6aef34fe25..113a0468ffcb 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -151,13 +151,13 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, hz = (t) ? t->speed_hz : spi->max_speed_hz; if (bits_per_word != 8) { dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", - __FUNCTION__, bits_per_word); + __func__, bits_per_word); return -EINVAL; } if (hz && xspi->speed_hz > hz) { dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n", - __FUNCTION__, hz); + __func__, hz); return -EINVAL; } @@ -181,7 +181,7 @@ static int xilinx_spi_setup(struct spi_device *spi) if (spi->mode & ~MODEBITS) { dev_err(&spi->dev, "%s, unsupported mode bits %x\n", - __FUNCTION__, spi->mode & ~MODEBITS); + __func__, spi->mode & ~MODEBITS); return -EINVAL; } @@ -190,7 +190,7 @@ static int xilinx_spi_setup(struct spi_device *spi) return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __FUNCTION__, spi->mode & MODEBITS, spi->bits_per_word, 0); + __func__, spi->mode & MODEBITS, spi->bits_per_word, 0); return 0; } diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 17e71d56f31e..4b628526df09 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -3,7 +3,7 @@ # menuconfig THERMAL - bool "Generic Thermal sysfs driver" + tristate "Generic Thermal sysfs driver" help Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal @@ -11,4 +11,4 @@ menuconfig THERMAL Each thermal zone contains its own temperature, trip points, cooling devices. All platforms with ACPI thermal support can use this driver. - If you want this support, you should say Y here. + If you want this support, you should say Y or M here. diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 8ef1232de376..31108a01c22e 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -2,4 +2,4 @@ # Makefile for sensor chip drivers. # -obj-$(CONFIG_THERMAL) += thermal.o +obj-$(CONFIG_THERMAL) += thermal_sys.o diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal_sys.c index 7f79bbf652d7..6098787341f3 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal_sys.c @@ -31,7 +31,7 @@ #include <linux/thermal.h> #include <linux/spinlock.h> -MODULE_AUTHOR("Zhang Rui") +MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL"); @@ -295,6 +295,164 @@ thermal_cooling_device_trip_point_show(struct device *dev, /* Device management */ +#if defined(CONFIG_HWMON) || \ + (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE)) +/* hwmon sys I/F */ +#include <linux/hwmon.h> +static LIST_HEAD(thermal_hwmon_list); + +static ssize_t +name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct thermal_hwmon_device *hwmon = dev->driver_data; + return sprintf(buf, "%s\n", hwmon->type); +} +static DEVICE_ATTR(name, 0444, name_show, NULL); + +static ssize_t +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct thermal_hwmon_attr *hwmon_attr + = container_of(attr, struct thermal_hwmon_attr, attr); + struct thermal_zone_device *tz + = container_of(hwmon_attr, struct thermal_zone_device, + temp_input); + + return tz->ops->get_temp(tz, buf); +} + +static ssize_t +temp_crit_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct thermal_hwmon_attr *hwmon_attr + = container_of(attr, struct thermal_hwmon_attr, attr); + struct thermal_zone_device *tz + = container_of(hwmon_attr, struct thermal_zone_device, + temp_crit); + + return tz->ops->get_trip_temp(tz, 0, buf); +} + + +static int +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) +{ + struct thermal_hwmon_device *hwmon; + int new_hwmon_device = 1; + int result; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(hwmon, &thermal_hwmon_list, node) + if (!strcmp(hwmon->type, tz->type)) { + new_hwmon_device = 0; + mutex_unlock(&thermal_list_lock); + goto register_sys_interface; + } + mutex_unlock(&thermal_list_lock); + + hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + INIT_LIST_HEAD(&hwmon->tz_list); + strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH); + hwmon->device = hwmon_device_register(NULL); + if (IS_ERR(hwmon->device)) { + result = PTR_ERR(hwmon->device); + goto free_mem; + } + hwmon->device->driver_data = hwmon; + result = device_create_file(hwmon->device, &dev_attr_name); + if (result) + goto unregister_hwmon_device; + + register_sys_interface: + tz->hwmon = hwmon; + hwmon->count++; + + snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, + "temp%d_input", hwmon->count); + tz->temp_input.attr.attr.name = tz->temp_input.name; + tz->temp_input.attr.attr.mode = 0444; + tz->temp_input.attr.show = temp_input_show; + result = device_create_file(hwmon->device, &tz->temp_input.attr); + if (result) + goto unregister_hwmon_device; + + if (tz->ops->get_crit_temp) { + unsigned long temperature; + if (!tz->ops->get_crit_temp(tz, &temperature)) { + snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, + "temp%d_crit", hwmon->count); + tz->temp_crit.attr.attr.name = tz->temp_crit.name; + tz->temp_crit.attr.attr.mode = 0444; + tz->temp_crit.attr.show = temp_crit_show; + result = device_create_file(hwmon->device, + &tz->temp_crit.attr); + if (result) + goto unregister_hwmon_device; + } + } + + mutex_lock(&thermal_list_lock); + if (new_hwmon_device) + list_add_tail(&hwmon->node, &thermal_hwmon_list); + list_add_tail(&tz->hwmon_node, &hwmon->tz_list); + mutex_unlock(&thermal_list_lock); + + return 0; + + unregister_hwmon_device: + device_remove_file(hwmon->device, &tz->temp_crit.attr); + device_remove_file(hwmon->device, &tz->temp_input.attr); + if (new_hwmon_device) { + device_remove_file(hwmon->device, &dev_attr_name); + hwmon_device_unregister(hwmon->device); + } + free_mem: + if (new_hwmon_device) + kfree(hwmon); + + return result; +} + +static void +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) +{ + struct thermal_hwmon_device *hwmon = tz->hwmon; + + tz->hwmon = NULL; + device_remove_file(hwmon->device, &tz->temp_input.attr); + device_remove_file(hwmon->device, &tz->temp_crit.attr); + + mutex_lock(&thermal_list_lock); + list_del(&tz->hwmon_node); + if (!list_empty(&hwmon->tz_list)) { + mutex_unlock(&thermal_list_lock); + return; + } + list_del(&hwmon->node); + mutex_unlock(&thermal_list_lock); + + device_remove_file(hwmon->device, &dev_attr_name); + hwmon_device_unregister(hwmon->device); + kfree(hwmon); +} +#else +static int +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) +{ + return 0; +} + +static void +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) +{ +} +#endif + + /** * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone * @tz: thermal zone device @@ -642,6 +800,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, goto unregister; } + result = thermal_add_hwmon_sysfs(tz); + if (result) + goto unregister; + mutex_lock(&thermal_list_lock); list_add_tail(&tz->node, &thermal_tz_list); if (ops->bind) @@ -700,6 +862,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) for (count = 0; count < tz->trips; count++) TRIP_POINT_ATTR_REMOVE(&tz->device, count); + thermal_remove_hwmon_sysfs(tz); release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); idr_destroy(&tz->idr); mutex_destroy(&tz->lock); diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 516a6400db43..a419c42e880e 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -17,6 +17,8 @@ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ +obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ + obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_PRINTER) += class/ diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index 86e64035edb0..be0b8daac9c7 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -19,7 +19,6 @@ if USB_ATM config USB_SPEEDTOUCH tristate "Speedtouch USB support" - depends on USB_ATM select FW_LOADER help Say Y here if you have an SpeedTouch USB or SpeedTouch 330 @@ -32,7 +31,6 @@ config USB_SPEEDTOUCH config USB_CXACRU tristate "Conexant AccessRunner USB support" - depends on USB_ATM select FW_LOADER help Say Y here if you have an ADSL USB modem based on the Conexant @@ -45,7 +43,6 @@ config USB_CXACRU config USB_UEAGLEATM tristate "ADI 930 and eagle USB DSL modem" - depends on USB_ATM select FW_LOADER help Say Y here if you have an ADSL USB modem based on the ADI 930 @@ -58,7 +55,6 @@ config USB_UEAGLEATM config USB_XUSBATM tristate "Other USB DSL modem support" - depends on USB_ATM help Say Y here if you have a DSL USB modem not explicitly supported by another USB DSL drivers. In order to use your modem you will need to diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index d470c72b737e..5ea3093bc40f 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -38,6 +38,7 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/mutex.h> +#include <asm/unaligned.h> #include "usbatm.h" @@ -573,7 +574,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ u32 *data, int size) { int ret, len; - u32 *buf; + __le32 *buf; int offb, offd; const int stride = CMD_PACKET_SIZE / (4 * 2) - 1; int buflen = ((size - 1) / stride + 1 + size * 2) * 4; @@ -837,7 +838,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, buf[offb++] = l; buf[offb++] = code1; buf[offb++] = code2; - *((u32 *) (buf + offb)) = cpu_to_le32(addr); + put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb)); offb += 4; addr += l; if(l) @@ -874,8 +875,9 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, int off; struct usbatm_data *usbatm = instance->usbatm; struct usb_device *usb_dev = usbatm->usb_dev; - u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct }; - u32 val; + __le16 signature[] = { usb_dev->descriptor.idVendor, + usb_dev->descriptor.idProduct }; + __le32 val; dbg("cxacru_upload_firmware"); @@ -955,7 +957,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, /* Load config data (le32), doing one packet at a time */ if (cf) for (off = 0; off < cf->size / 4; ) { - u32 buf[CMD_PACKET_SIZE / 4 - 1]; + __le32 buf[CMD_PACKET_SIZE / 4 - 1]; int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1); buf[0] = cpu_to_le32(len); for (i = 0; i < len; i++, off++) { diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index abb7d7410e63..5f71ff3aee35 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -305,8 +305,6 @@ enum { */ #define FW_GET_BYTE(p) *((__u8 *) (p)) -#define FW_GET_WORD(p) le16_to_cpu(get_unaligned((__le16 *) (p))) -#define FW_GET_LONG(p) le32_to_cpu(get_unaligned((__le32 *) (p))) #define FW_DIR "ueagle-atm/" #define NB_MODEM 4 @@ -621,7 +619,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte if (size < 4) goto err_fw_corrupted; - crc = FW_GET_LONG(pfw); + crc = get_unaligned_le32(pfw); pfw += 4; size -= 4; if (crc32_be(0, pfw, size) != crc) @@ -640,7 +638,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte while (size > 3) { u8 len = FW_GET_BYTE(pfw); - u16 add = FW_GET_WORD(pfw + 1); + u16 add = get_unaligned_le16(pfw + 1); size -= len + 3; if (size < 0) @@ -738,7 +736,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len) for (i = 0; i < pagecount; i++) { - pageoffset = FW_GET_LONG(dsp + p); + pageoffset = get_unaligned_le32(dsp + p); p += 4; if (pageoffset == 0) @@ -759,7 +757,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len) return 1; pp += 2; /* skip blockaddr */ - blocksize = FW_GET_WORD(dsp + pp); + blocksize = get_unaligned_le16(dsp + pp); pp += 2; /* enough space for block data? */ @@ -928,7 +926,7 @@ static void uea_load_page_e1(struct work_struct *work) goto bad1; p += 4 * pageno; - pageoffset = FW_GET_LONG(p); + pageoffset = get_unaligned_le32(p); if (pageoffset == 0) goto bad1; @@ -945,10 +943,10 @@ static void uea_load_page_e1(struct work_struct *work) bi.wOvlOffset = cpu_to_le16(ovl | 0x8000); for (i = 0; i < blockcount; i++) { - blockaddr = FW_GET_WORD(p); + blockaddr = get_unaligned_le16(p); p += 2; - blocksize = FW_GET_WORD(p); + blocksize = get_unaligned_le16(p); p += 2; bi.wSize = cpu_to_le16(blocksize); @@ -996,7 +994,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); bi.dwSize = cpu_to_be32(blocksize); - bi.dwAddress = swab32(blockidx->PageAddress); + bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress)); uea_dbg(INS_TO_USBDEV(sc), "sending block %u for DSP page %u size %u address %x\n", @@ -1040,7 +1038,7 @@ static void uea_load_page_e4(struct work_struct *work) return; p = (struct l1_code *) sc->dsp_firm->data; - if (pageno >= p->page_header[0].PageNumber) { + if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) { uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); return; } @@ -1065,7 +1063,7 @@ static void uea_load_page_e4(struct work_struct *work) bi.bPageNumber = 0xff; bi.wReserved = cpu_to_be16(UEA_RESERVED); bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); - bi.dwAddress = swab32(p->page_header[0].PageAddress); + bi.dwAddress = cpu_to_be32(le32_to_cpu(p->page_header[0].PageAddress)); /* send block info through the IDMA pipe */ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) @@ -1152,9 +1150,9 @@ static int uea_cmv_e1(struct uea_softc *sc, cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); - put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); + put_unaligned_le32(address, &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); - put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); + put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData); ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) @@ -1646,7 +1644,7 @@ static int request_cmvs(struct uea_softc *sc, if (size < 5) goto err_fw_corrupted; - crc = FW_GET_LONG(data); + crc = get_unaligned_le32(data); data += 4; size -= 4; if (crc32_be(0, data, size) != crc) @@ -1696,9 +1694,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) "please update your firmware\n"); for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), - FW_GET_WORD(&cmvs_v1[i].offset), - FW_GET_LONG(&cmvs_v1[i].data)); + ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address), + get_unaligned_le16(&cmvs_v1[i].offset), + get_unaligned_le32(&cmvs_v1[i].data)); if (ret < 0) goto out; } @@ -1706,9 +1704,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), - (u16) FW_GET_LONG(&cmvs_v2[i].offset), - FW_GET_LONG(&cmvs_v2[i].data)); + ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address), + (u16) get_unaligned_le32(&cmvs_v2[i].offset), + get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out; } @@ -1759,10 +1757,10 @@ static int uea_send_cmvs_e4(struct uea_softc *sc) for (i = 0; i < len; i++) { ret = uea_write_cmv_e4(sc, 1, - FW_GET_LONG(&cmvs_v2[i].group), - FW_GET_LONG(&cmvs_v2[i].address), - FW_GET_LONG(&cmvs_v2[i].offset), - FW_GET_LONG(&cmvs_v2[i].data)); + get_unaligned_le32(&cmvs_v2[i].group), + get_unaligned_le32(&cmvs_v2[i].address), + get_unaligned_le32(&cmvs_v2[i].offset), + get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out; } @@ -1964,7 +1962,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) if (UEA_CHIP_VERSION(sc) == ADI930 && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { cmv->wIndex = cpu_to_le16(dsc->idx); - put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress); cmv->wOffsetAddress = cpu_to_le16(dsc->offset); } else goto bad2; @@ -1978,11 +1976,11 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) /* in case of MEMACCESS */ if (le16_to_cpu(cmv->wIndex) != dsc->idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address || le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; - sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); + sc->data = get_unaligned_le32(&cmv->dwData); sc->data = sc->data << 16 | sc->data >> 16; wake_up_cmv_ack(sc); diff --git a/drivers/usb/c67x00/Makefile b/drivers/usb/c67x00/Makefile new file mode 100644 index 000000000000..868bc41b5980 --- /dev/null +++ b/drivers/usb/c67x00/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Cypress C67X00 USB Controller +# + +ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG + +obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o + +c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c new file mode 100644 index 000000000000..5633bc5c8bf2 --- /dev/null +++ b/drivers/usb/c67x00/c67x00-drv.c @@ -0,0 +1,243 @@ +/* + * c67x00-drv.c: Cypress C67X00 USB Common infrastructure + * + * Copyright (C) 2006-2008 Barco N.V. + * Derived from the Cypress cy7c67200/300 ezusb linux driver and + * based on multiple host controller drivers inside the linux kernel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +/* + * This file implements the common infrastructure for using the c67x00. + * It is both the link between the platform configuration and subdrivers and + * the link between the common hardware parts and the subdrivers (e.g. + * interrupt handling). + * + * The c67x00 has 2 SIE's (serial interface engine) wich can be configured + * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG). + * + * Depending on the platform configuration, the SIE's are created and + * the corresponding subdriver is initialized (c67x00_probe_sie). + */ + +#include <linux/device.h> +#include <linux/io.h> +#include <linux/list.h> +#include <linux/usb.h> +#include <linux/usb/c67x00.h> + +#include "c67x00.h" +#include "c67x00-hcd.h" + +static void c67x00_probe_sie(struct c67x00_sie *sie, + struct c67x00_device *dev, int sie_num) +{ + spin_lock_init(&sie->lock); + sie->dev = dev; + sie->sie_num = sie_num; + sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num); + + switch (sie->mode) { + case C67X00_SIE_HOST: + c67x00_hcd_probe(sie); + break; + + case C67X00_SIE_UNUSED: + dev_info(sie_dev(sie), + "Not using SIE %d as requested\n", sie->sie_num); + break; + + default: + dev_err(sie_dev(sie), + "Unsupported configuration: 0x%x for SIE %d\n", + sie->mode, sie->sie_num); + break; + } +} + +static void c67x00_remove_sie(struct c67x00_sie *sie) +{ + switch (sie->mode) { + case C67X00_SIE_HOST: + c67x00_hcd_remove(sie); + break; + + default: + break; + } +} + +static irqreturn_t c67x00_irq(int irq, void *__dev) +{ + struct c67x00_device *c67x00 = __dev; + struct c67x00_sie *sie; + u16 msg, int_status; + int i, count = 8; + + int_status = c67x00_ll_hpi_status(c67x00); + if (!int_status) + return IRQ_NONE; + + while (int_status != 0 && (count-- >= 0)) { + c67x00_ll_irq(c67x00, int_status); + for (i = 0; i < C67X00_SIES; i++) { + sie = &c67x00->sie[i]; + msg = 0; + if (int_status & SIEMSG_FLG(i)) + msg = c67x00_ll_fetch_siemsg(c67x00, i); + if (sie->irq) + sie->irq(sie, int_status, msg); + } + int_status = c67x00_ll_hpi_status(c67x00); + } + + if (int_status) + dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! " + "status = 0x%04x\n", int_status); + + return IRQ_HANDLED; +} + +/* ------------------------------------------------------------------------- */ + +static int __devinit c67x00_drv_probe(struct platform_device *pdev) +{ + struct c67x00_device *c67x00; + struct c67x00_platform_data *pdata; + struct resource *res, *res2; + int ret, i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -ENODEV; + + c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL); + if (!c67x00) + return -ENOMEM; + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + dev_err(&pdev->dev, "Memory region busy\n"); + ret = -EBUSY; + goto request_mem_failed; + } + c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1); + if (!c67x00->hpi.base) { + dev_err(&pdev->dev, "Unable to map HPI registers\n"); + ret = -EIO; + goto map_failed; + } + + spin_lock_init(&c67x00->hpi.lock); + c67x00->hpi.regstep = pdata->hpi_regstep; + c67x00->pdata = pdev->dev.platform_data; + c67x00->pdev = pdev; + + c67x00_ll_init(c67x00); + c67x00_ll_hpi_reg_init(c67x00); + + ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto request_irq_failed; + } + + ret = c67x00_ll_reset(c67x00); + if (ret) { + dev_err(&pdev->dev, "Device reset failed\n"); + goto reset_failed; + } + + for (i = 0; i < C67X00_SIES; i++) + c67x00_probe_sie(&c67x00->sie[i], c67x00, i); + + platform_set_drvdata(pdev, c67x00); + + return 0; + + reset_failed: + free_irq(res2->start, c67x00); + request_irq_failed: + iounmap(c67x00->hpi.base); + map_failed: + release_mem_region(res->start, res->end - res->start + 1); + request_mem_failed: + kfree(c67x00); + + return ret; +} + +static int __devexit c67x00_drv_remove(struct platform_device *pdev) +{ + struct c67x00_device *c67x00 = platform_get_drvdata(pdev); + struct resource *res; + int i; + + for (i = 0; i < C67X00_SIES; i++) + c67x00_remove_sie(&c67x00->sie[i]); + + c67x00_ll_release(c67x00); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) + free_irq(res->start, c67x00); + + iounmap(c67x00->hpi.base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, res->end - res->start + 1); + + kfree(c67x00); + + return 0; +} + +static struct platform_driver c67x00_driver = { + .probe = c67x00_drv_probe, + .remove = __devexit_p(c67x00_drv_remove), + .driver = { + .owner = THIS_MODULE, + .name = "c67x00", + }, +}; +MODULE_ALIAS("platform:c67x00"); + +static int __init c67x00_init(void) +{ + return platform_driver_register(&c67x00_driver); +} + +static void __exit c67x00_exit(void) +{ + platform_driver_unregister(&c67x00_driver); +} + +module_init(c67x00_init); +module_exit(c67x00_exit); + +MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely"); +MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c new file mode 100644 index 000000000000..a22b887f4e9e --- /dev/null +++ b/drivers/usb/c67x00/c67x00-hcd.c @@ -0,0 +1,412 @@ +/* + * c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver + * + * Copyright (C) 2006-2008 Barco N.V. + * Derived from the Cypress cy7c67200/300 ezusb linux driver and + * based on multiple host controller drivers inside the linux kernel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/usb.h> + +#include "c67x00.h" +#include "c67x00-hcd.h" + +/* -------------------------------------------------------------------------- + * Root Hub Support + */ + +static __u8 c67x00_hub_des[] = { + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x02, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, /* (per-port OC, no power switching) */ + 0x32, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; ** 7 Ports max ** */ + 0xff, /* __u8 PortPwrCtrlMask; ** 7 ports max ** */ +}; + +static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port) +{ + struct c67x00_hcd *c67x00 = sie->private_data; + unsigned long flags; + + c67x00_ll_husb_reset(sie, port); + + spin_lock_irqsave(&c67x00->lock, flags); + c67x00_ll_husb_reset_port(sie, port); + spin_unlock_irqrestore(&c67x00->lock, flags); + + c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT); +} + +static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); + struct c67x00_sie *sie = c67x00->sie; + u16 status; + int i; + + *buf = 0; + status = c67x00_ll_usb_get_status(sie); + for (i = 0; i < C67X00_PORTS; i++) + if (status & PORT_CONNECT_CHANGE(i)) + *buf |= (1 << i); + + /* bit 0 denotes hub change, b1..n port change */ + *buf <<= 1; + + return !!*buf; +} + +static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); + struct c67x00_sie *sie = c67x00->sie; + u16 status, usb_status; + int len = 0; + unsigned int port = wIndex-1; + u16 wPortChange, wPortStatus; + + switch (typeReq) { + + case GetHubStatus: + *(__le32 *) buf = cpu_to_le32(0); + len = 4; /* hub power */ + break; + + case GetPortStatus: + if (wIndex > C67X00_PORTS) + return -EPIPE; + + status = c67x00_ll_usb_get_status(sie); + usb_status = c67x00_ll_get_usb_ctl(sie); + + wPortChange = 0; + if (status & PORT_CONNECT_CHANGE(port)) + wPortChange |= USB_PORT_STAT_C_CONNECTION; + + wPortStatus = USB_PORT_STAT_POWER; + if (!(status & PORT_SE0_STATUS(port))) + wPortStatus |= USB_PORT_STAT_CONNECTION; + if (usb_status & LOW_SPEED_PORT(port)) { + wPortStatus |= USB_PORT_STAT_LOW_SPEED; + c67x00->low_speed_ports |= (1 << port); + } else + c67x00->low_speed_ports &= ~(1 << port); + + if (usb_status & SOF_EOP_EN(port)) + wPortStatus |= USB_PORT_STAT_ENABLE; + + *(__le16 *) buf = cpu_to_le16(wPortStatus); + *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange); + len = 4; + break; + + case SetHubFeature: /* We don't implement these */ + case ClearHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + case C_HUB_LOCAL_POWER: + len = 0; + break; + + default: + return -EPIPE; + } + break; + + case SetPortFeature: + if (wIndex > C67X00_PORTS) + return -EPIPE; + + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + dev_dbg(c67x00_hcd_dev(c67x00), + "SetPortFeature %d (SUSPEND)\n", port); + len = 0; + break; + + case USB_PORT_FEAT_RESET: + c67x00_hub_reset_host_port(sie, port); + len = 0; + break; + + case USB_PORT_FEAT_POWER: + /* Power always enabled */ + len = 0; + break; + + default: + dev_dbg(c67x00_hcd_dev(c67x00), + "%s: SetPortFeature %d (0x%04x) Error!\n", + __func__, port, wValue); + return -EPIPE; + } + break; + + case ClearPortFeature: + if (wIndex > C67X00_PORTS) + return -EPIPE; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + /* Reset the port so that the c67x00 also notices the + * disconnect */ + c67x00_hub_reset_host_port(sie, port); + len = 0; + break; + + case USB_PORT_FEAT_C_ENABLE: + dev_dbg(c67x00_hcd_dev(c67x00), + "ClearPortFeature (%d): C_ENABLE\n", port); + len = 0; + break; + + case USB_PORT_FEAT_SUSPEND: + dev_dbg(c67x00_hcd_dev(c67x00), + "ClearPortFeature (%d): SUSPEND\n", port); + len = 0; + break; + + case USB_PORT_FEAT_C_SUSPEND: + dev_dbg(c67x00_hcd_dev(c67x00), + "ClearPortFeature (%d): C_SUSPEND\n", port); + len = 0; + break; + + case USB_PORT_FEAT_POWER: + dev_dbg(c67x00_hcd_dev(c67x00), + "ClearPortFeature (%d): POWER\n", port); + return -EPIPE; + + case USB_PORT_FEAT_C_CONNECTION: + c67x00_ll_usb_clear_status(sie, + PORT_CONNECT_CHANGE(port)); + len = 0; + break; + + case USB_PORT_FEAT_C_OVER_CURRENT: + dev_dbg(c67x00_hcd_dev(c67x00), + "ClearPortFeature (%d): OVER_CURRENT\n", port); + len = 0; + break; + + case USB_PORT_FEAT_C_RESET: + dev_dbg(c67x00_hcd_dev(c67x00), + "ClearPortFeature (%d): C_RESET\n", port); + len = 0; + break; + + default: + dev_dbg(c67x00_hcd_dev(c67x00), + "%s: ClearPortFeature %d (0x%04x) Error!\n", + __func__, port, wValue); + return -EPIPE; + } + break; + + case GetHubDescriptor: + len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength); + memcpy(buf, c67x00_hub_des, len); + break; + + default: + dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__); + return -EPIPE; + } + + return 0; +} + +/* --------------------------------------------------------------------- + * Main part of host controller driver + */ + +/** + * c67x00_hcd_irq + * + * This function is called from the interrupt handler in c67x00-drv.c + */ +static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg) +{ + struct c67x00_hcd *c67x00 = sie->private_data; + struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00); + + /* Handle sie message flags */ + if (msg) { + if (msg & HUSB_TDListDone) + c67x00_sched_kick(c67x00); + else + dev_warn(c67x00_hcd_dev(c67x00), + "Unknown SIE msg flag(s): 0x%04x\n", msg); + } + + if (unlikely(hcd->state == HC_STATE_HALT)) + return; + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) + return; + + /* Handle Start of frame events */ + if (int_status & SOFEOP_FLG(sie->sie_num)) { + c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG); + c67x00_sched_kick(c67x00); + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + } +} + +/** + * c67x00_hcd_start: Host controller start hook + */ +static int c67x00_hcd_start(struct usb_hcd *hcd) +{ + hcd->uses_new_polling = 1; + hcd->state = HC_STATE_RUNNING; + hcd->poll_rh = 1; + + return 0; +} + +/** + * c67x00_hcd_stop: Host controller stop hook + */ +static void c67x00_hcd_stop(struct usb_hcd *hcd) +{ + /* Nothing to do */ +} + +static int c67x00_hcd_get_frame(struct usb_hcd *hcd) +{ + struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); + u16 temp_val; + + dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__); + temp_val = c67x00_ll_husb_get_frame(c67x00->sie); + temp_val &= HOST_FRAME_MASK; + return temp_val ? (temp_val - 1) : HOST_FRAME_MASK; +} + +static struct hc_driver c67x00_hc_driver = { + .description = "c67x00-hcd", + .product_desc = "Cypress C67X00 Host Controller", + .hcd_priv_size = sizeof(struct c67x00_hcd), + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = c67x00_hcd_start, + .stop = c67x00_hcd_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = c67x00_urb_enqueue, + .urb_dequeue = c67x00_urb_dequeue, + .endpoint_disable = c67x00_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = c67x00_hcd_get_frame, + + /* + * root hub support + */ + .hub_status_data = c67x00_hub_status_data, + .hub_control = c67x00_hub_control, +}; + +/* --------------------------------------------------------------------- + * Setup/Teardown routines + */ + +int c67x00_hcd_probe(struct c67x00_sie *sie) +{ + struct c67x00_hcd *c67x00; + struct usb_hcd *hcd; + unsigned long flags; + int retval; + + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie"); + if (!hcd) { + retval = -ENOMEM; + goto err0; + } + c67x00 = hcd_to_c67x00_hcd(hcd); + + spin_lock_init(&c67x00->lock); + c67x00->sie = sie; + + INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]); + INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]); + INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]); + INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]); + c67x00->urb_count = 0; + INIT_LIST_HEAD(&c67x00->td_list); + c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num); + c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num); + c67x00->max_frame_bw = MAX_FRAME_BW_STD; + + c67x00_ll_husb_init_host_port(sie); + + init_completion(&c67x00->endpoint_disable); + retval = c67x00_sched_start_scheduler(c67x00); + if (retval) + goto err1; + + retval = usb_add_hcd(hcd, 0, 0); + if (retval) { + dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n", + __func__, retval); + goto err2; + } + + spin_lock_irqsave(&sie->lock, flags); + sie->private_data = c67x00; + sie->irq = c67x00_hcd_irq; + spin_unlock_irqrestore(&sie->lock, flags); + + return retval; + + err2: + c67x00_sched_stop_scheduler(c67x00); + err1: + usb_put_hcd(hcd); + err0: + return retval; +} + +/* may be called with controller, bus, and devices active */ +void c67x00_hcd_remove(struct c67x00_sie *sie) +{ + struct c67x00_hcd *c67x00 = sie->private_data; + struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00); + + c67x00_sched_stop_scheduler(c67x00); + usb_remove_hcd(hcd); + usb_put_hcd(hcd); +} diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h new file mode 100644 index 000000000000..e8c6d94b2514 --- /dev/null +++ b/drivers/usb/c67x00/c67x00-hcd.h @@ -0,0 +1,133 @@ +/* + * c67x00-hcd.h: Cypress C67X00 USB HCD + * + * Copyright (C) 2006-2008 Barco N.V. + * Derived from the Cypress cy7c67200/300 ezusb linux driver and + * based on multiple host controller drivers inside the linux kernel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +#ifndef _USB_C67X00_HCD_H +#define _USB_C67X00_HCD_H + +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/usb.h> +#include "../core/hcd.h" +#include "c67x00.h" + +/* + * The following parameters depend on the CPU speed, bus speed, ... + * These can be tuned for specific use cases, e.g. if isochronous transfers + * are very important, bandwith can be sacrificed to guarantee that the + * 1ms deadline will be met. + * If bulk transfers are important, the MAX_FRAME_BW can be increased, + * but some (or many) isochronous deadlines might not be met. + * + * The values are specified in bittime. + */ + +/* + * The current implementation switches between _STD (default) and _ISO (when + * isochronous transfers are scheduled), in order to optimize the throughput + * in normal cicrumstances, but also provide good isochronous behaviour. + * + * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms + * frames; there are 12000 bit times per frame. + */ + +#define TOTAL_FRAME_BW 12000 +#define DEFAULT_EOT 2250 + +#define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT) +#define MAX_FRAME_BW_ISO 2400 + +/* + * Periodic transfers may only use 90% of the full frame, but as + * we currently don't even use 90% of the full frame, we may + * use the full usable time for periodic transfers. + */ +#define MAX_PERIODIC_BW(full_bw) full_bw + +/* -------------------------------------------------------------------------- */ + +struct c67x00_hcd { + spinlock_t lock; + struct c67x00_sie *sie; + unsigned int low_speed_ports; /* bitmask of low speed ports */ + unsigned int urb_count; + unsigned int urb_iso_count; + + struct list_head list[4]; /* iso, int, ctrl, bulk */ +#if PIPE_BULK != 3 +#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3" +#endif + + /* USB bandwidth allocated to td_list */ + int bandwidth_allocated; + /* USB bandwidth allocated for isoc/int transfer */ + int periodic_bw_allocated; + struct list_head td_list; + int max_frame_bw; + + u16 td_base_addr; + u16 buf_base_addr; + u16 next_td_addr; + u16 next_buf_addr; + + struct tasklet_struct tasklet; + + struct completion endpoint_disable; + + u16 current_frame; + u16 last_frame; +}; + +static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd) +{ + return (struct c67x00_hcd *)(hcd->hcd_priv); +} + +static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00) +{ + return container_of((void *)c67x00, struct usb_hcd, hcd_priv); +} + +/* --------------------------------------------------------------------- + * Functions used by c67x00-drv + */ + +int c67x00_hcd_probe(struct c67x00_sie *sie); +void c67x00_hcd_remove(struct c67x00_sie *sie); + +/* --------------------------------------------------------------------- + * Transfer Descriptor scheduling functions + */ +int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); +int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); +void c67x00_endpoint_disable(struct usb_hcd *hcd, + struct usb_host_endpoint *ep); + +void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg); +void c67x00_sched_kick(struct c67x00_hcd *c67x00); +int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00); +void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00); + +#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller) + +#endif /* _USB_C67X00_HCD_H */ diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c new file mode 100644 index 000000000000..f3430b372f09 --- /dev/null +++ b/drivers/usb/c67x00/c67x00-ll-hpi.c @@ -0,0 +1,480 @@ +/* + * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI + * + * Copyright (C) 2006-2008 Barco N.V. + * Derived from the Cypress cy7c67200/300 ezusb linux driver and + * based on multiple host controller drivers inside the linux kernel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +#include <asm/byteorder.h> +#include <linux/io.h> +#include <linux/usb/c67x00.h> +#include "c67x00.h" + +#define COMM_REGS 14 + +struct c67x00_lcp_int_data { + u16 regs[COMM_REGS]; +}; + +/* -------------------------------------------------------------------------- */ +/* Interface definitions */ + +#define COMM_ACK 0x0FED +#define COMM_NAK 0xDEAD + +#define COMM_RESET 0xFA50 +#define COMM_EXEC_INT 0xCE01 +#define COMM_INT_NUM 0x01C2 + +/* Registers 0 to COMM_REGS-1 */ +#define COMM_R(x) (0x01C4 + 2 * (x)) + +#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0) +#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6) +#define HUSB_pEOT 0x01B4 + +/* Software interrupts */ +/* 114, 115: */ +#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072) +#define HUSB_RESET_INT 0x0074 + +#define SUSB_INIT_INT 0x0071 +#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2) + +/* ----------------------------------------------------------------------- + * HPI implementation + * + * The c67x00 chip also support control via SPI or HSS serial + * interfaces. However, this driver assumes that register access can + * be performed from IRQ context. While this is a safe assuption with + * the HPI interface, it is not true for the serial interfaces. + */ + +/* HPI registers */ +#define HPI_DATA 0 +#define HPI_MAILBOX 1 +#define HPI_ADDR 2 +#define HPI_STATUS 3 + +static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg) +{ + return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep); +} + +static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value) +{ + __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep); +} + +static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg) +{ + hpi_write_reg(dev, HPI_ADDR, reg); + return hpi_read_reg(dev, HPI_DATA); +} + +static u16 hpi_read_word(struct c67x00_device *dev, u16 reg) +{ + u16 value; + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + value = hpi_read_word_nolock(dev, reg); + spin_unlock_irqrestore(&dev->hpi.lock, flags); + + return value; +} + +static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value) +{ + hpi_write_reg(dev, HPI_ADDR, reg); + hpi_write_reg(dev, HPI_DATA, value); +} + +static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + hpi_write_word_nolock(dev, reg, value); + spin_unlock_irqrestore(&dev->hpi.lock, flags); +} + +/* + * Only data is little endian, addr has cpu endianess + */ +static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr, + u16 *data, u16 count) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&dev->hpi.lock, flags); + + hpi_write_reg(dev, HPI_ADDR, addr); + for (i = 0; i < count; i++) + hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++)); + + spin_unlock_irqrestore(&dev->hpi.lock, flags); +} + +/* + * Only data is little endian, addr has cpu endianess + */ +static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr, + u16 *data, u16 count) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&dev->hpi.lock, flags); + hpi_write_reg(dev, HPI_ADDR, addr); + for (i = 0; i < count; i++) + *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA)); + + spin_unlock_irqrestore(&dev->hpi.lock, flags); +} + +static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask) +{ + u16 value; + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + value = hpi_read_word_nolock(dev, reg); + hpi_write_word_nolock(dev, reg, value | mask); + spin_unlock_irqrestore(&dev->hpi.lock, flags); +} + +static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask) +{ + u16 value; + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + value = hpi_read_word_nolock(dev, reg); + hpi_write_word_nolock(dev, reg, value & ~mask); + spin_unlock_irqrestore(&dev->hpi.lock, flags); +} + +static u16 hpi_recv_mbox(struct c67x00_device *dev) +{ + u16 value; + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + value = hpi_read_reg(dev, HPI_MAILBOX); + spin_unlock_irqrestore(&dev->hpi.lock, flags); + + return value; +} + +static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + hpi_write_reg(dev, HPI_MAILBOX, value); + spin_unlock_irqrestore(&dev->hpi.lock, flags); + + return value; +} + +u16 c67x00_ll_hpi_status(struct c67x00_device *dev) +{ + u16 value; + unsigned long flags; + + spin_lock_irqsave(&dev->hpi.lock, flags); + value = hpi_read_reg(dev, HPI_STATUS); + spin_unlock_irqrestore(&dev->hpi.lock, flags); + + return value; +} + +void c67x00_ll_hpi_reg_init(struct c67x00_device *dev) +{ + int i; + + hpi_recv_mbox(dev); + c67x00_ll_hpi_status(dev); + hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0); + + for (i = 0; i < C67X00_SIES; i++) { + hpi_write_word(dev, SIEMSG_REG(i), 0); + hpi_read_word(dev, SIEMSG_REG(i)); + } +} + +void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie) +{ + hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG, + SOFEOP_TO_HPI_EN(sie->sie_num)); +} + +void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie) +{ + hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG, + SOFEOP_TO_HPI_EN(sie->sie_num)); +} + +/* -------------------------------------------------------------------------- */ +/* Transactions */ + +static inline u16 ll_recv_msg(struct c67x00_device *dev) +{ + u16 res; + + res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ); + WARN_ON(!res); + + return (res == 0) ? -EIO : 0; +} + +/* -------------------------------------------------------------------------- */ +/* General functions */ + +u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num) +{ + u16 val; + + val = hpi_read_word(dev, SIEMSG_REG(sie_num)); + /* clear register to allow next message */ + hpi_write_word(dev, SIEMSG_REG(sie_num), 0); + + return val; +} + +u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie) +{ + return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)); +} + +/** + * c67x00_ll_usb_clear_status - clear the USB status bits + */ +void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits) +{ + hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits); +} + +u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie) +{ + return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num)); +} + +/* -------------------------------------------------------------------------- */ + +static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr, + struct c67x00_lcp_int_data *data) +{ + int i, rc; + + mutex_lock(&dev->hpi.lcp.mutex); + hpi_write_word(dev, COMM_INT_NUM, nr); + for (i = 0; i < COMM_REGS; i++) + hpi_write_word(dev, COMM_R(i), data->regs[i]); + hpi_send_mbox(dev, COMM_EXEC_INT); + rc = ll_recv_msg(dev); + mutex_unlock(&dev->hpi.lcp.mutex); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* Host specific functions */ + +void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value) +{ + mutex_lock(&dev->hpi.lcp.mutex); + hpi_write_word(dev, HUSB_pEOT, value); + mutex_unlock(&dev->hpi.lcp.mutex); +} + +static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie) +{ + struct c67x00_device *dev = sie->dev; + struct c67x00_lcp_int_data data; + int rc; + + rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data); + BUG_ON(rc); /* No return path for error code; crash spectacularly */ +} + +void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port) +{ + struct c67x00_device *dev = sie->dev; + struct c67x00_lcp_int_data data; + int rc; + + data.regs[0] = 50; /* Reset USB port for 50ms */ + data.regs[1] = port | (sie->sie_num << 1); + rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data); + BUG_ON(rc); /* No return path for error code; crash spectacularly */ +} + +void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr) +{ + hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr); +} + +u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie) +{ + return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num)); +} + +u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie) +{ + return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num)); +} + +void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie) +{ + /* Set port into host mode */ + hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE); + c67x00_ll_husb_sie_init(sie); + /* Clear interrupts */ + c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK); + /* Check */ + if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE)) + dev_warn(sie_dev(sie), + "SIE %d not set to host mode\n", sie->sie_num); +} + +void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port) +{ + /* Clear connect change */ + c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port)); + + /* Enable interrupts */ + hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG, + SOFEOP_TO_CPU_EN(sie->sie_num)); + hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num), + SOF_EOP_IRQ_EN | DONE_IRQ_EN); + + /* Enable pull down transistors */ + hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port)); +} + +/* -------------------------------------------------------------------------- */ + +void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status) +{ + if ((int_status & MBX_OUT_FLG) == 0) + return; + + dev->hpi.lcp.last_msg = hpi_recv_mbox(dev); + complete(&dev->hpi.lcp.msg_received); +} + +/* -------------------------------------------------------------------------- */ + +int c67x00_ll_reset(struct c67x00_device *dev) +{ + int rc; + + mutex_lock(&dev->hpi.lcp.mutex); + hpi_send_mbox(dev, COMM_RESET); + rc = ll_recv_msg(dev); + mutex_unlock(&dev->hpi.lcp.mutex); + + return rc; +} + +/* -------------------------------------------------------------------------- */ + +/** + * c67x00_ll_write_mem_le16 - write into c67x00 memory + * Only data is little endian, addr has cpu endianess. + */ +void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr, + void *data, int len) +{ + u8 *buf = data; + + /* Sanity check */ + if (addr + len > 0xffff) { + dev_err(&dev->pdev->dev, + "Trying to write beyond writable region!\n"); + return; + } + + if (addr & 0x01) { + /* unaligned access */ + u16 tmp; + tmp = hpi_read_word(dev, addr - 1); + tmp = (tmp & 0x00ff) | (*buf++ << 8); + hpi_write_word(dev, addr - 1, tmp); + addr++; + len--; + } + + hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2); + buf += len & ~0x01; + addr += len & ~0x01; + len &= 0x01; + + if (len) { + u16 tmp; + tmp = hpi_read_word(dev, addr); + tmp = (tmp & 0xff00) | *buf; + hpi_write_word(dev, addr, tmp); + } +} + +/** + * c67x00_ll_read_mem_le16 - read from c67x00 memory + * Only data is little endian, addr has cpu endianess. + */ +void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr, + void *data, int len) +{ + u8 *buf = data; + + if (addr & 0x01) { + /* unaligned access */ + u16 tmp; + tmp = hpi_read_word(dev, addr - 1); + *buf++ = (tmp >> 8) & 0x00ff; + addr++; + len--; + } + + hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2); + buf += len & ~0x01; + addr += len & ~0x01; + len &= 0x01; + + if (len) { + u16 tmp; + tmp = hpi_read_word(dev, addr); + *buf = tmp & 0x00ff; + } +} + +/* -------------------------------------------------------------------------- */ + +void c67x00_ll_init(struct c67x00_device *dev) +{ + mutex_init(&dev->hpi.lcp.mutex); + init_completion(&dev->hpi.lcp.msg_received); +} + +void c67x00_ll_release(struct c67x00_device *dev) +{ +} diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c new file mode 100644 index 000000000000..85dfe2965661 --- /dev/null +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -0,0 +1,1170 @@ +/* + * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling + * + * Copyright (C) 2006-2008 Barco N.V. + * Derived from the Cypress cy7c67200/300 ezusb linux driver and + * based on multiple host controller drivers inside the linux kernel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +#include <linux/kthread.h> + +#include "c67x00.h" +#include "c67x00-hcd.h" + +/* + * These are the stages for a control urb, they are kept + * in both urb->interval and td->privdata. + */ +#define SETUP_STAGE 0 +#define DATA_STAGE 1 +#define STATUS_STAGE 2 + +/* -------------------------------------------------------------------------- */ + +/** + * struct c67x00_ep_data: Host endpoint data structure + */ +struct c67x00_ep_data { + struct list_head queue; + struct list_head node; + struct usb_host_endpoint *hep; + struct usb_device *dev; + u16 next_frame; /* For int/isoc transactions */ +}; + +/** + * struct c67x00_td + * + * Hardware parts are little endiannes, SW in CPU endianess. + */ +struct c67x00_td { + /* HW specific part */ + __le16 ly_base_addr; /* Bytes 0-1 */ + __le16 port_length; /* Bytes 2-3 */ + u8 pid_ep; /* Byte 4 */ + u8 dev_addr; /* Byte 5 */ + u8 ctrl_reg; /* Byte 6 */ + u8 status; /* Byte 7 */ + u8 retry_cnt; /* Byte 8 */ +#define TT_OFFSET 2 +#define TT_CONTROL 0 +#define TT_ISOCHRONOUS 1 +#define TT_BULK 2 +#define TT_INTERRUPT 3 + u8 residue; /* Byte 9 */ + __le16 next_td_addr; /* Bytes 10-11 */ + /* SW part */ + struct list_head td_list; + u16 td_addr; + void *data; + struct urb *urb; + unsigned long privdata; + + /* These are needed for handling the toggle bits: + * an urb can be dequeued while a td is in progress + * after checking the td, the toggle bit might need to + * be fixed */ + struct c67x00_ep_data *ep_data; + unsigned int pipe; +}; + +struct c67x00_urb_priv { + struct list_head hep_node; + struct urb *urb; + int port; + int cnt; /* packet number for isoc */ + int status; + struct c67x00_ep_data *ep_data; +}; + +#define td_udev(td) ((td)->ep_data->dev) + +#define CY_TD_SIZE 12 + +#define TD_PIDEP_OFFSET 0x04 +#define TD_PIDEPMASK_PID 0xF0 +#define TD_PIDEPMASK_EP 0x0F +#define TD_PORTLENMASK_DL 0x02FF +#define TD_PORTLENMASK_PN 0xC000 + +#define TD_STATUS_OFFSET 0x07 +#define TD_STATUSMASK_ACK 0x01 +#define TD_STATUSMASK_ERR 0x02 +#define TD_STATUSMASK_TMOUT 0x04 +#define TD_STATUSMASK_SEQ 0x08 +#define TD_STATUSMASK_SETUP 0x10 +#define TD_STATUSMASK_OVF 0x20 +#define TD_STATUSMASK_NAK 0x40 +#define TD_STATUSMASK_STALL 0x80 + +#define TD_ERROR_MASK (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \ + TD_STATUSMASK_STALL) + +#define TD_RETRYCNT_OFFSET 0x08 +#define TD_RETRYCNTMASK_ACT_FLG 0x10 +#define TD_RETRYCNTMASK_TX_TYPE 0x0C +#define TD_RETRYCNTMASK_RTY_CNT 0x03 + +#define TD_RESIDUE_OVERFLOW 0x80 + +#define TD_PID_IN 0x90 + +/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */ +#define td_residue(td) ((__s8)(td->residue)) +#define td_ly_base_addr(td) (__le16_to_cpu((td)->ly_base_addr)) +#define td_port_length(td) (__le16_to_cpu((td)->port_length)) +#define td_next_td_addr(td) (__le16_to_cpu((td)->next_td_addr)) + +#define td_active(td) ((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG) +#define td_length(td) (td_port_length(td) & TD_PORTLENMASK_DL) + +#define td_sequence_ok(td) (!td->status || \ + (!(td->status & TD_STATUSMASK_SEQ) == \ + !(td->ctrl_reg & SEQ_SEL))) + +#define td_acked(td) (!td->status || \ + (td->status & TD_STATUSMASK_ACK)) +#define td_actual_bytes(td) (td_length(td) - td_residue(td)) + +/* -------------------------------------------------------------------------- */ + +#ifdef DEBUG + +/** + * dbg_td - Dump the contents of the TD + */ +static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) +{ + struct device *dev = c67x00_hcd_dev(c67x00); + + dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr); + dev_dbg(dev, "urb: 0x%p\n", td->urb); + dev_dbg(dev, "endpoint: %4d\n", usb_pipeendpoint(td->pipe)); + dev_dbg(dev, "pipeout: %4d\n", usb_pipeout(td->pipe)); + dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td)); + dev_dbg(dev, "port_length: 0x%04x\n", td_port_length(td)); + dev_dbg(dev, "pid_ep: 0x%02x\n", td->pid_ep); + dev_dbg(dev, "dev_addr: 0x%02x\n", td->dev_addr); + dev_dbg(dev, "ctrl_reg: 0x%02x\n", td->ctrl_reg); + dev_dbg(dev, "status: 0x%02x\n", td->status); + dev_dbg(dev, "retry_cnt: 0x%02x\n", td->retry_cnt); + dev_dbg(dev, "residue: 0x%02x\n", td->residue); + dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td)); + dev_dbg(dev, "data:"); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, + td->data, td_length(td), 1); +} +#else /* DEBUG */ + +static inline void +dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { } + +#endif /* DEBUG */ + +/* -------------------------------------------------------------------------- */ +/* Helper functions */ + +static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00) +{ + return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK; +} + +/** + * frame_add + * Software wraparound for framenumbers. + */ +static inline u16 frame_add(u16 a, u16 b) +{ + return (a + b) & HOST_FRAME_MASK; +} + +/** + * frame_after - is frame a after frame b + */ +static inline int frame_after(u16 a, u16 b) +{ + return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) < + (HOST_FRAME_MASK / 2); +} + +/** + * frame_after_eq - is frame a after or equal to frame b + */ +static inline int frame_after_eq(u16 a, u16 b) +{ + return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) < + (HOST_FRAME_MASK / 2); +} + +/* -------------------------------------------------------------------------- */ + +/** + * c67x00_release_urb - remove link from all tds to this urb + * Disconnects the urb from it's tds, so that it can be given back. + * pre: urb->hcpriv != NULL + */ +static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb) +{ + struct c67x00_td *td; + struct c67x00_urb_priv *urbp; + + BUG_ON(!urb); + + c67x00->urb_count--; + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + c67x00->urb_iso_count--; + if (c67x00->urb_iso_count == 0) + c67x00->max_frame_bw = MAX_FRAME_BW_STD; + } + + /* TODO this might be not so efficient when we've got many urbs! + * Alternatives: + * * only clear when needed + * * keep a list of tds with each urbp + */ + list_for_each_entry(td, &c67x00->td_list, td_list) + if (urb == td->urb) + td->urb = NULL; + + urbp = urb->hcpriv; + urb->hcpriv = NULL; + list_del(&urbp->hep_node); + kfree(urbp); +} + +/* -------------------------------------------------------------------------- */ + +static struct c67x00_ep_data * +c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb) +{ + struct usb_host_endpoint *hep = urb->ep; + struct c67x00_ep_data *ep_data; + int type; + + c67x00->current_frame = c67x00_get_current_frame_number(c67x00); + + /* Check if endpoint already has a c67x00_ep_data struct allocated */ + if (hep->hcpriv) { + ep_data = hep->hcpriv; + if (frame_after(c67x00->current_frame, ep_data->next_frame)) + ep_data->next_frame = + frame_add(c67x00->current_frame, 1); + return hep->hcpriv; + } + + /* Allocate and initialize a new c67x00 endpoint data structure */ + ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC); + if (!ep_data) + return NULL; + + INIT_LIST_HEAD(&ep_data->queue); + INIT_LIST_HEAD(&ep_data->node); + ep_data->hep = hep; + + /* hold a reference to udev as long as this endpoint lives, + * this is needed to possibly fix the data toggle */ + ep_data->dev = usb_get_dev(urb->dev); + hep->hcpriv = ep_data; + + /* For ISOC and INT endpoints, start ASAP: */ + ep_data->next_frame = frame_add(c67x00->current_frame, 1); + + /* Add the endpoint data to one of the pipe lists; must be added + in order of endpoint address */ + type = usb_pipetype(urb->pipe); + if (list_empty(&ep_data->node)) { + list_add(&ep_data->node, &c67x00->list[type]); + } else { + struct c67x00_ep_data *prev; + + list_for_each_entry(prev, &c67x00->list[type], node) { + if (prev->hep->desc.bEndpointAddress > + hep->desc.bEndpointAddress) { + list_add(&ep_data->node, prev->node.prev); + break; + } + } + } + + return ep_data; +} + +static int c67x00_ep_data_free(struct usb_host_endpoint *hep) +{ + struct c67x00_ep_data *ep_data = hep->hcpriv; + + if (!ep_data) + return 0; + + if (!list_empty(&ep_data->queue)) + return -EBUSY; + + usb_put_dev(ep_data->dev); + list_del(&ep_data->queue); + list_del(&ep_data->node); + + kfree(ep_data); + hep->hcpriv = NULL; + + return 0; +} + +void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); + unsigned long flags; + + if (!list_empty(&ep->urb_list)) + dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n"); + + spin_lock_irqsave(&c67x00->lock, flags); + + /* loop waiting for all transfers in the endpoint queue to complete */ + while (c67x00_ep_data_free(ep)) { + /* Drop the lock so we can sleep waiting for the hardware */ + spin_unlock_irqrestore(&c67x00->lock, flags); + + /* it could happen that we reinitialize this completion, while + * somebody was waiting for that completion. The timeout and + * while loop handle such cases, but this might be improved */ + INIT_COMPLETION(c67x00->endpoint_disable); + c67x00_sched_kick(c67x00); + wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ); + + spin_lock_irqsave(&c67x00->lock, flags); + } + + spin_unlock_irqrestore(&c67x00->lock, flags); +} + +/* -------------------------------------------------------------------------- */ + +static inline int get_root_port(struct usb_device *dev) +{ + while (dev->parent->parent) + dev = dev->parent; + return dev->portnum; +} + +int c67x00_urb_enqueue(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags) +{ + int ret; + unsigned long flags; + struct c67x00_urb_priv *urbp; + struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); + int port = get_root_port(urb->dev)-1; + + spin_lock_irqsave(&c67x00->lock, flags); + + /* Make sure host controller is running */ + if (!HC_IS_RUNNING(hcd->state)) { + ret = -ENODEV; + goto err_not_linked; + } + + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto err_not_linked; + + /* Allocate and initialize urb private data */ + urbp = kzalloc(sizeof(*urbp), mem_flags); + if (!urbp) { + ret = -ENOMEM; + goto err_urbp; + } + + INIT_LIST_HEAD(&urbp->hep_node); + urbp->urb = urb; + urbp->port = port; + + urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb); + + if (!urbp->ep_data) { + ret = -ENOMEM; + goto err_epdata; + } + + /* TODO claim bandwidth with usb_claim_bandwidth? + * also release it somewhere! */ + + urb->hcpriv = urbp; + + urb->actual_length = 0; /* Nothing received/transmitted yet */ + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + urb->interval = SETUP_STAGE; + break; + case PIPE_INTERRUPT: + break; + case PIPE_BULK: + break; + case PIPE_ISOCHRONOUS: + if (c67x00->urb_iso_count == 0) + c67x00->max_frame_bw = MAX_FRAME_BW_ISO; + c67x00->urb_iso_count++; + /* Assume always URB_ISO_ASAP, FIXME */ + if (list_empty(&urbp->ep_data->queue)) + urb->start_frame = urbp->ep_data->next_frame; + else { + /* Go right after the last one */ + struct urb *last_urb; + + last_urb = list_entry(urbp->ep_data->queue.prev, + struct c67x00_urb_priv, + hep_node)->urb; + urb->start_frame = + frame_add(last_urb->start_frame, + last_urb->number_of_packets * + last_urb->interval); + } + urbp->cnt = 0; + break; + } + + /* Add the URB to the endpoint queue */ + list_add_tail(&urbp->hep_node, &urbp->ep_data->queue); + + /* If this is the only URB, kick start the controller */ + if (!c67x00->urb_count++) + c67x00_ll_hpi_enable_sofeop(c67x00->sie); + + c67x00_sched_kick(c67x00); + spin_unlock_irqrestore(&c67x00->lock, flags); + + return 0; + +err_epdata: + kfree(urbp); +err_urbp: + usb_hcd_unlink_urb_from_ep(hcd, urb); +err_not_linked: + spin_unlock_irqrestore(&c67x00->lock, flags); + + return ret; +} + +int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ + struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); + unsigned long flags; + int rc; + + spin_lock_irqsave(&c67x00->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + + c67x00_release_urb(c67x00, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + + spin_unlock(&c67x00->lock); + usb_hcd_giveback_urb(hcd, urb, status); + spin_lock(&c67x00->lock); + + spin_unlock_irqrestore(&c67x00->lock, flags); + + return 0; + + done: + spin_unlock_irqrestore(&c67x00->lock, flags); + return rc; +} + +/* -------------------------------------------------------------------------- */ + +/* + * pre: c67x00 locked, urb unlocked + */ +static void +c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status) +{ + struct c67x00_urb_priv *urbp; + + if (!urb) + return; + + urbp = urb->hcpriv; + urbp->status = status; + + list_del_init(&urbp->hep_node); + + c67x00_release_urb(c67x00, urb); + usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb); + spin_unlock(&c67x00->lock); + usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status); + spin_lock(&c67x00->lock); +} + +/* -------------------------------------------------------------------------- */ + +static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb, + int len, int periodic) +{ + struct c67x00_urb_priv *urbp = urb->hcpriv; + int bit_time; + + /* According to the C67x00 BIOS user manual, page 3-18,19, the + * following calculations provide the full speed bit times for + * a transaction. + * + * FS(in) = 112.5 + 9.36*BC + HOST_DELAY + * FS(in,iso) = 90.5 + 9.36*BC + HOST_DELAY + * FS(out) = 112.5 + 9.36*BC + HOST_DELAY + * FS(out,iso) = 78.4 + 9.36*BC + HOST_DELAY + * LS(in) = 802.4 + 75.78*BC + HOST_DELAY + * LS(out) = 802.6 + 74.67*BC + HOST_DELAY + * + * HOST_DELAY == 106 for the c67200 and c67300. + */ + + /* make calculations in 1/100 bit times to maintain resolution */ + if (urbp->ep_data->dev->speed == USB_SPEED_LOW) { + /* Low speed pipe */ + if (usb_pipein(urb->pipe)) + bit_time = 80240 + 7578*len; + else + bit_time = 80260 + 7467*len; + } else { + /* FS pipes */ + if (usb_pipeisoc(urb->pipe)) + bit_time = usb_pipein(urb->pipe) ? 9050 : 7840; + else + bit_time = 11250; + bit_time += 936*len; + } + + /* Scale back down to integer bit times. Use a host delay of 106. + * (this is the only place it is used) */ + bit_time = ((bit_time+50) / 100) + 106; + + if (unlikely(bit_time + c67x00->bandwidth_allocated >= + c67x00->max_frame_bw)) + return -EMSGSIZE; + + if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >= + c67x00->td_base_addr + SIE_TD_SIZE)) + return -EMSGSIZE; + + if (unlikely(c67x00->next_buf_addr + len >= + c67x00->buf_base_addr + SIE_TD_BUF_SIZE)) + return -EMSGSIZE; + + if (periodic) { + if (unlikely(bit_time + c67x00->periodic_bw_allocated >= + MAX_PERIODIC_BW(c67x00->max_frame_bw))) + return -EMSGSIZE; + c67x00->periodic_bw_allocated += bit_time; + } + + c67x00->bandwidth_allocated += bit_time; + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** + * td_addr and buf_addr must be word aligned + */ +static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb, + void *data, int len, int pid, int toggle, + unsigned long privdata) +{ + struct c67x00_td *td; + struct c67x00_urb_priv *urbp = urb->hcpriv; + const __u8 active_flag = 1, retry_cnt = 1; + __u8 cmd = 0; + int tt = 0; + + if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe) + || usb_pipeint(urb->pipe))) + return -EMSGSIZE; /* Not really an error, but expected */ + + td = kzalloc(sizeof(*td), GFP_ATOMIC); + if (!td) + return -ENOMEM; + + td->pipe = urb->pipe; + td->ep_data = urbp->ep_data; + + if ((td_udev(td)->speed == USB_SPEED_LOW) && + !(c67x00->low_speed_ports & (1 << urbp->port))) + cmd |= PREAMBLE_EN; + + switch (usb_pipetype(td->pipe)) { + case PIPE_ISOCHRONOUS: + tt = TT_ISOCHRONOUS; + cmd |= ISO_EN; + break; + case PIPE_CONTROL: + tt = TT_CONTROL; + break; + case PIPE_BULK: + tt = TT_BULK; + break; + case PIPE_INTERRUPT: + tt = TT_INTERRUPT; + break; + } + + if (toggle) + cmd |= SEQ_SEL; + + cmd |= ARM_EN; + + /* SW part */ + td->td_addr = c67x00->next_td_addr; + c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE; + + /* HW part */ + td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr); + td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) | + (urbp->port << 14) | (len & 0x3FF)); + td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) | + (usb_pipeendpoint(td->pipe) & 0xF); + td->dev_addr = usb_pipedevice(td->pipe) & 0x7F; + td->ctrl_reg = cmd; + td->status = 0; + td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt; + td->residue = 0; + td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr); + + /* SW part */ + td->data = data; + td->urb = urb; + td->privdata = privdata; + + c67x00->next_buf_addr += (len + 1) & ~0x01; /* properly align */ + + list_add_tail(&td->td_list, &c67x00->td_list); + return 0; +} + +static inline void c67x00_release_td(struct c67x00_td *td) +{ + list_del_init(&td->td_list); + kfree(td); +} + +/* -------------------------------------------------------------------------- */ + +static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb) +{ + int remaining; + int toggle; + int pid; + int ret = 0; + int maxps; + int need_empty; + + toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)); + remaining = urb->transfer_buffer_length - urb->actual_length; + + maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + + need_empty = (urb->transfer_flags & URB_ZERO_PACKET) && + usb_pipeout(urb->pipe) && !(remaining % maxps); + + while (remaining || need_empty) { + int len; + char *td_buf; + + len = (remaining > maxps) ? maxps : remaining; + if (!len) + need_empty = 0; + + pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN; + td_buf = urb->transfer_buffer + urb->transfer_buffer_length - + remaining; + ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle, + DATA_STAGE); + if (ret) + return ret; /* td wasn't created */ + + toggle ^= 1; + remaining -= len; + if (usb_pipecontrol(urb->pipe)) + break; + } + + return 0; +} + +/** + * return 0 in case more bandwidth is available, else errorcode + */ +static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb) +{ + int ret; + int pid; + + switch (urb->interval) { + default: + case SETUP_STAGE: + ret = c67x00_create_td(c67x00, urb, urb->setup_packet, + 8, USB_PID_SETUP, 0, SETUP_STAGE); + if (ret) + return ret; + urb->interval = SETUP_STAGE; + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), 1); + break; + case DATA_STAGE: + if (urb->transfer_buffer_length) { + ret = c67x00_add_data_urb(c67x00, urb); + if (ret) + return ret; + break; + } /* else fallthrough */ + case STATUS_STAGE: + pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN; + ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1, + STATUS_STAGE); + if (ret) + return ret; + break; + } + + return 0; +} + +/* + * return 0 in case more bandwidth is available, else errorcode + */ +static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb) +{ + struct c67x00_urb_priv *urbp = urb->hcpriv; + + if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) { + urbp->ep_data->next_frame = + frame_add(urbp->ep_data->next_frame, urb->interval); + return c67x00_add_data_urb(c67x00, urb); + } + return 0; +} + +static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb) +{ + struct c67x00_urb_priv *urbp = urb->hcpriv; + + if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) { + char *td_buf; + int len, pid, ret; + + BUG_ON(urbp->cnt >= urb->number_of_packets); + + td_buf = urb->transfer_buffer + + urb->iso_frame_desc[urbp->cnt].offset; + len = urb->iso_frame_desc[urbp->cnt].length; + pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN; + + ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0, + urbp->cnt); + if (ret) { + printk(KERN_DEBUG "create failed: %d\n", ret); + urb->iso_frame_desc[urbp->cnt].actual_length = 0; + urb->iso_frame_desc[urbp->cnt].status = ret; + if (urbp->cnt + 1 == urb->number_of_packets) + c67x00_giveback_urb(c67x00, urb, 0); + } + + urbp->ep_data->next_frame = + frame_add(urbp->ep_data->next_frame, urb->interval); + urbp->cnt++; + } + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type, + int (*add)(struct c67x00_hcd *, struct urb *)) +{ + struct c67x00_ep_data *ep_data; + struct urb *urb; + + /* traverse every endpoint on the list */ + list_for_each_entry(ep_data, &c67x00->list[type], node) { + if (!list_empty(&ep_data->queue)) { + /* and add the first urb */ + /* isochronous transfer rely on this */ + urb = list_entry(ep_data->queue.next, + struct c67x00_urb_priv, + hep_node)->urb; + add(c67x00, urb); + } + } +} + +static void c67x00_fill_frame(struct c67x00_hcd *c67x00) +{ + struct c67x00_td *td, *ttd; + + /* Check if we can proceed */ + if (!list_empty(&c67x00->td_list)) { + dev_warn(c67x00_hcd_dev(c67x00), + "TD list not empty! This should not happen!\n"); + list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) { + dbg_td(c67x00, td, "Unprocessed td"); + c67x00_release_td(td); + } + } + + /* Reinitialize variables */ + c67x00->bandwidth_allocated = 0; + c67x00->periodic_bw_allocated = 0; + + c67x00->next_td_addr = c67x00->td_base_addr; + c67x00->next_buf_addr = c67x00->buf_base_addr; + + /* Fill the list */ + c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb); + c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb); + c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb); + c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb); +} + +/* -------------------------------------------------------------------------- */ + +/** + * Get TD from C67X00 + */ +static inline void +c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td) +{ + c67x00_ll_read_mem_le16(c67x00->sie->dev, + td->td_addr, td, CY_TD_SIZE); + + if (usb_pipein(td->pipe) && td_actual_bytes(td)) + c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td), + td->data, td_actual_bytes(td)); +} + +static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td) +{ + if (td->status & TD_STATUSMASK_ERR) { + dbg_td(c67x00, td, "ERROR_FLAG"); + return -EILSEQ; + } + if (td->status & TD_STATUSMASK_STALL) { + /* dbg_td(c67x00, td, "STALL"); */ + return -EPIPE; + } + if (td->status & TD_STATUSMASK_TMOUT) { + dbg_td(c67x00, td, "TIMEOUT"); + return -ETIMEDOUT; + } + + return 0; +} + +static inline int c67x00_end_of_data(struct c67x00_td *td) +{ + int maxps, need_empty, remaining; + struct urb *urb = td->urb; + int act_bytes; + + act_bytes = td_actual_bytes(td); + + if (unlikely(!act_bytes)) + return 1; /* This was an empty packet */ + + maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe)); + + if (unlikely(act_bytes < maxps)) + return 1; /* Smaller then full packet */ + + remaining = urb->transfer_buffer_length - urb->actual_length; + need_empty = (urb->transfer_flags & URB_ZERO_PACKET) && + usb_pipeout(urb->pipe) && !(remaining % maxps); + + if (unlikely(!remaining && !need_empty)) + return 1; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Remove all td's from the list which come + * after last_td and are meant for the same pipe. + * This is used when a short packet has occured */ +static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00, + struct c67x00_td *last_td) +{ + struct c67x00_td *td, *tmp; + td = last_td; + tmp = last_td; + while (td->td_list.next != &c67x00->td_list) { + td = list_entry(td->td_list.next, struct c67x00_td, td_list); + if (td->pipe == last_td->pipe) { + c67x00_release_td(td); + td = tmp; + } + tmp = td; + } +} + +/* -------------------------------------------------------------------------- */ + +static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00, + struct c67x00_td *td) +{ + struct urb *urb = td->urb; + + if (!urb) + return; + + urb->actual_length += td_actual_bytes(td); + + switch (usb_pipetype(td->pipe)) { + /* isochronous tds are handled separately */ + case PIPE_CONTROL: + switch (td->privdata) { + case SETUP_STAGE: + urb->interval = + urb->transfer_buffer_length ? + DATA_STAGE : STATUS_STAGE; + /* Don't count setup_packet with normal data: */ + urb->actual_length = 0; + break; + + case DATA_STAGE: + if (c67x00_end_of_data(td)) { + urb->interval = STATUS_STAGE; + c67x00_clear_pipe(c67x00, td); + } + break; + + case STATUS_STAGE: + urb->interval = 0; + c67x00_giveback_urb(c67x00, urb, 0); + break; + } + break; + + case PIPE_INTERRUPT: + case PIPE_BULK: + if (unlikely(c67x00_end_of_data(td))) { + c67x00_clear_pipe(c67x00, td); + c67x00_giveback_urb(c67x00, urb, 0); + } + break; + } +} + +static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td) +{ + struct urb *urb = td->urb; + struct c67x00_urb_priv *urbp; + int cnt; + + if (!urb) + return; + + urbp = urb->hcpriv; + cnt = td->privdata; + + if (td->status & TD_ERROR_MASK) + urb->error_count++; + + urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td); + urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td); + if (cnt + 1 == urb->number_of_packets) /* Last packet */ + c67x00_giveback_urb(c67x00, urb, 0); +} + +/* -------------------------------------------------------------------------- */ + +/** + * c67x00_check_td_list - handle tds which have been processed by the c67x00 + * pre: current_td == 0 + */ +static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00) +{ + struct c67x00_td *td, *tmp; + struct urb *urb; + int ack_ok; + int clear_endpoint; + + list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) { + /* get the TD */ + c67x00_parse_td(c67x00, td); + urb = td->urb; /* urb can be NULL! */ + ack_ok = 0; + clear_endpoint = 1; + + /* Handle isochronous transfers separately */ + if (usb_pipeisoc(td->pipe)) { + clear_endpoint = 0; + c67x00_handle_isoc(c67x00, td); + goto cont; + } + + /* When an error occurs, all td's for that pipe go into an + * inactive state. This state matches successful transfers so + * we must make sure not to service them. */ + if (td->status & TD_ERROR_MASK) { + c67x00_giveback_urb(c67x00, urb, + c67x00_td_to_error(c67x00, td)); + goto cont; + } + + if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) || + !td_acked(td)) + goto cont; + + /* Sequence ok and acked, don't need to fix toggle */ + ack_ok = 1; + + if (unlikely(td->status & TD_STATUSMASK_OVF)) { + if (td_residue(td) & TD_RESIDUE_OVERFLOW) { + /* Overflow */ + c67x00_giveback_urb(c67x00, urb, -EOVERFLOW); + goto cont; + } + } + + clear_endpoint = 0; + c67x00_handle_successful_td(c67x00, td); + +cont: + if (clear_endpoint) + c67x00_clear_pipe(c67x00, td); + if (ack_ok) + usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe), + usb_pipeout(td->pipe), + !(td->ctrl_reg & SEQ_SEL)); + /* next in list could have been removed, due to clear_pipe! */ + tmp = list_entry(td->td_list.next, typeof(*td), td_list); + c67x00_release_td(td); + } +} + +/* -------------------------------------------------------------------------- */ + +static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00) +{ + /* If all tds are processed, we can check the previous frame (if + * there was any) and start our next frame. + */ + return !c67x00_ll_husb_get_current_td(c67x00->sie); +} + +/** + * Send td to C67X00 + */ +static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td) +{ + int len = td_length(td); + + if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN)) + c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td), + td->data, len); + + c67x00_ll_write_mem_le16(c67x00->sie->dev, + td->td_addr, td, CY_TD_SIZE); +} + +static void c67x00_send_frame(struct c67x00_hcd *c67x00) +{ + struct c67x00_td *td; + + if (list_empty(&c67x00->td_list)) + dev_warn(c67x00_hcd_dev(c67x00), + "%s: td list should not be empty here!\n", + __func__); + + list_for_each_entry(td, &c67x00->td_list, td_list) { + if (td->td_list.next == &c67x00->td_list) + td->next_td_addr = 0; /* Last td in list */ + + c67x00_send_td(c67x00, td); + } + + c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr); +} + +/* -------------------------------------------------------------------------- */ + +/** + * c67x00_do_work - Schedulers state machine + */ +static void c67x00_do_work(struct c67x00_hcd *c67x00) +{ + spin_lock(&c67x00->lock); + /* Make sure all tds are processed */ + if (!c67x00_all_tds_processed(c67x00)) + goto out; + + c67x00_check_td_list(c67x00); + + /* no td's are being processed (current == 0) + * and all have been "checked" */ + complete(&c67x00->endpoint_disable); + + if (!list_empty(&c67x00->td_list)) + goto out; + + c67x00->current_frame = c67x00_get_current_frame_number(c67x00); + if (c67x00->current_frame == c67x00->last_frame) + goto out; /* Don't send tds in same frame */ + c67x00->last_frame = c67x00->current_frame; + + /* If no urbs are scheduled, our work is done */ + if (!c67x00->urb_count) { + c67x00_ll_hpi_disable_sofeop(c67x00->sie); + goto out; + } + + c67x00_fill_frame(c67x00); + if (!list_empty(&c67x00->td_list)) + /* TD's have been added to the frame */ + c67x00_send_frame(c67x00); + + out: + spin_unlock(&c67x00->lock); +} + +/* -------------------------------------------------------------------------- */ + +static void c67x00_sched_tasklet(unsigned long __c67x00) +{ + struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00; + c67x00_do_work(c67x00); +} + +void c67x00_sched_kick(struct c67x00_hcd *c67x00) +{ + tasklet_hi_schedule(&c67x00->tasklet); +} + +int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00) +{ + tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet, + (unsigned long)c67x00); + return 0; +} + +void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00) +{ + tasklet_kill(&c67x00->tasklet); +} diff --git a/drivers/usb/c67x00/c67x00.h b/drivers/usb/c67x00/c67x00.h new file mode 100644 index 000000000000..a26e9ded0f32 --- /dev/null +++ b/drivers/usb/c67x00/c67x00.h @@ -0,0 +1,294 @@ +/* + * c67x00.h: Cypress C67X00 USB register and field definitions + * + * Copyright (C) 2006-2008 Barco N.V. + * Derived from the Cypress cy7c67200/300 ezusb linux driver and + * based on multiple host controller drivers inside the linux kernel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + */ + +#ifndef _USB_C67X00_H +#define _USB_C67X00_H + +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/completion.h> +#include <linux/mutex.h> + +/* --------------------------------------------------------------------- + * Cypress C67x00 register definitions + */ + +/* Hardware Revision Register */ +#define HW_REV_REG 0xC004 + +/* General USB registers */ +/* ===================== */ + +/* USB Control Register */ +#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A) + +#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400) +#define HOST_MODE 0x0200 +#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080) +#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001) + +/* USB status register - Notice it has different content in hcd/udc mode */ +#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090) + +#define EP0_IRQ_FLG 0x0001 +#define EP1_IRQ_FLG 0x0002 +#define EP2_IRQ_FLG 0x0004 +#define EP3_IRQ_FLG 0x0008 +#define EP4_IRQ_FLG 0x0010 +#define EP5_IRQ_FLG 0x0020 +#define EP6_IRQ_FLG 0x0040 +#define EP7_IRQ_FLG 0x0080 +#define RESET_IRQ_FLG 0x0100 +#define SOF_EOP_IRQ_FLG 0x0200 +#define ID_IRQ_FLG 0x4000 +#define VBUS_IRQ_FLG 0x8000 + +/* USB Host only registers */ +/* ======================= */ + +/* Host n Control Register */ +#define HOST_CTL_REG(x) ((x) ? 0xC0A0 : 0xC080) + +#define PREAMBLE_EN 0x0080 /* Preamble enable */ +#define SEQ_SEL 0x0040 /* Data Toggle Sequence Bit Select */ +#define ISO_EN 0x0010 /* Isochronous enable */ +#define ARM_EN 0x0001 /* Arm operation */ + +/* Host n Interrupt Enable Register */ +#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C) + +#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */ +#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */ +#define ID_IRQ_EN 0x4000 /* ID interrupt enable */ +#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */ +#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */ + +/* USB status register */ +#define HOST_STAT_MASK 0x02FD +#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010) +#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004) + +/* Host Frame Register */ +#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096) + +#define HOST_FRAME_MASK 0x07FF + +/* USB Peripheral only registers */ +/* ============================= */ + +/* Device n Port Sel reg */ +#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084) + +/* Device n Interrupt Enable Register */ +#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C) + +#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \ + ? (0x0280 + (ep << 4)) \ + : (0x0200 + (ep << 4))) +#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \ + ? (0x0286 + (ep << 4)) \ + : (0x0206 + (ep << 4))) + +#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E)) + +/* HPI registers */ +/* ============= */ + +/* HPI Status register */ +#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10)) +#define SIEMSG_FLG(x) (1 << (4 + (x))) +#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002) +#define DONE_FLG(x) (1 << (2 + (x))) +#define RESUME_FLG(x) (1 << (6 + (x))) +#define MBX_OUT_FLG 0x0001 /* Message out available */ +#define MBX_IN_FLG 0x0100 +#define ID_FLG 0x4000 +#define VBUS_FLG 0x8000 + +/* Interrupt routing register */ +#define HPI_IRQ_ROUTING_REG 0x0142 + +#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001) +#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002) +#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004) +#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040) +#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800) +#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400) +#define ID_TO_HPI_ENABLE 0x4000 +#define VBUS_TO_HPI_ENABLE 0x8000 + +/* SIE msg registers */ +#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144) + +#define HUSB_TDListDone 0x1000 + +#define SUSB_EP0_MSG 0x0001 +#define SUSB_EP1_MSG 0x0002 +#define SUSB_EP2_MSG 0x0004 +#define SUSB_EP3_MSG 0x0008 +#define SUSB_EP4_MSG 0x0010 +#define SUSB_EP5_MSG 0x0020 +#define SUSB_EP6_MSG 0x0040 +#define SUSB_EP7_MSG 0x0080 +#define SUSB_RST_MSG 0x0100 +#define SUSB_SOF_MSG 0x0200 +#define SUSB_CFG_MSG 0x0400 +#define SUSB_SUS_MSG 0x0800 +#define SUSB_ID_MSG 0x4000 +#define SUSB_VBUS_MSG 0x8000 + +/* BIOS interrupt routines */ + +#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81) +#define SUSBx_SEND_INT(x) ((x) ? 96 : 80) + +#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4) +#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6) +#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8) + +#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */ +#define SIE_TD_SIZE 0x200 /* size of the td list */ +#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */ + +#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0) +#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE) + +/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */ +#define CY_UDC_REQ_HEADER_BASE 0x1100 +/* 8- byte request headers for IN/OUT transfers */ +#define CY_UDC_REQ_HEADER_SIZE 8 + +#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \ + ((ep_num) * CY_UDC_REQ_HEADER_SIZE)) +#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8)) + +#define CY_UDC_BIOS_REPLACE_BASE 0x1800 +#define CY_UDC_REQ_BUFFER_BASE 0x2000 +#define CY_UDC_REQ_BUFFER_SIZE 0x0400 +#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \ + ((ep_num) * CY_UDC_REQ_BUFFER_SIZE)) + +/* --------------------------------------------------------------------- + * Driver data structures + */ + +struct c67x00_device; + +/** + * struct c67x00_sie - Common data associated with a SIE + * @lock: lock to protect this struct and the associated chip registers + * @private_data: subdriver dependent data + * @irq: subdriver dependent irq handler, set NULL when not used + * @dev: link to common driver structure + * @sie_num: SIE number on chip, starting from 0 + * @mode: SIE mode (host/peripheral/otg/not used) + */ +struct c67x00_sie { + /* Entries to be used by the subdrivers */ + spinlock_t lock; /* protect this structure */ + void *private_data; + void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg); + + /* Read only: */ + struct c67x00_device *dev; + int sie_num; + int mode; +}; + +#define sie_dev(s) (&(s)->dev->pdev->dev) + +/** + * struct c67x00_lcp + */ +struct c67x00_lcp { + /* Internal use only */ + struct mutex mutex; + struct completion msg_received; + u16 last_msg; +}; + +/* + * struct c67x00_hpi + */ +struct c67x00_hpi { + void __iomem *base; + int regstep; + spinlock_t lock; + struct c67x00_lcp lcp; +}; + +#define C67X00_SIES 2 +#define C67X00_PORTS 2 + +/** + * struct c67x00_device - Common data associated with a c67x00 instance + * @hpi: hpi addresses + * @sie: array of sie's on this chip + * @pdev: platform device of instance + * @pdata: configuration provided by the platform + */ +struct c67x00_device { + struct c67x00_hpi hpi; + struct c67x00_sie sie[C67X00_SIES]; + struct platform_device *pdev; + struct c67x00_platform_data *pdata; +}; + +/* --------------------------------------------------------------------- + * Low level interface functions + */ + +/* Host Port Interface (HPI) functions */ +u16 c67x00_ll_hpi_status(struct c67x00_device *dev); +void c67x00_ll_hpi_reg_init(struct c67x00_device *dev); +void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie); +void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie); + +/* General functions */ +u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num); +u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie); +void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits); +u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie); +void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr, + void *data, int len); +void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr, + void *data, int len); + +/* Host specific functions */ +void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value); +void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port); +void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr); +u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie); +u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie); +void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie); +void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port); + +/* Called by c67x00_irq to handle lcp interrupts */ +void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status); + +/* Setup and teardown */ +void c67x00_ll_init(struct c67x00_device *dev); +void c67x00_ll_release(struct c67x00_device *dev); +int c67x00_ll_reset(struct c67x00_device *dev); + +#endif /* _USB_C67X00_H */ diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7b572e75e73c..cefe7f2c6f75 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -280,7 +280,7 @@ static void acm_ctrl_irq(struct urb *urb) case USB_CDC_NOTIFY_SERIAL_STATE: - newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); + newctrl = get_unaligned_le16(data); if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 8607846e3c3f..1d253dd4ea81 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -773,7 +773,7 @@ int __init usbfs_init(void) usb_register_notify(&usbfs_nb); /* create mount point for usbfs */ - usbdir = proc_mkdir("usb", proc_bus); + usbdir = proc_mkdir("bus/usb", NULL); return 0; } @@ -783,6 +783,6 @@ void usbfs_cleanup(void) usb_unregister_notify(&usbfs_nb); unregister_filesystem(&usb_fs_type); if (usbdir) - remove_proc_entry("usb", proc_bus); + remove_proc_entry("bus/usb", NULL); } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index e819e5359d57..3e69266e1f4d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -394,7 +394,9 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, if (!io->urbs) goto nomem; - urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; + urb_flags = URB_NO_INTERRUPT; + if (dma) + urb_flags |= URB_NO_TRANSFER_DMA_MAP; if (usb_pipein(pipe)) urb_flags |= URB_SHORT_NOT_OK; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index f7b54651dd42..6e784d2db423 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -231,6 +231,26 @@ config SUPERH_BUILT_IN_M66592 However, this problem is improved if change a value of NET_IP_ALIGN to 4. +config USB_GADGET_PXA27X + boolean "PXA 27x" + depends on ARCH_PXA && PXA27x + help + Intel's PXA 27x series XScale ARM v5TE processors include + an integrated full speed USB 1.1 device controller. + + It has up to 23 endpoints, as well as endpoint zero (for + control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "pxa27x_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_PXA27X + tristate + depends on USB_GADGET_PXA27X + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_GOKU boolean "Toshiba TC86C001 'Goku-S'" depends on PCI diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index c3aab80b6c76..12357255d740 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o +obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index fc6f3483be44..ce337cb5d137 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -328,6 +328,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) u32 tmp; unsigned long iflags; u8 udc_csr_epix; + unsigned maxpacket; if (!usbep || usbep->name == ep0_string @@ -354,9 +355,10 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) writel(tmp, &dev->ep[ep->num].regs->ctl); /* set max packet size */ + maxpacket = le16_to_cpu(desc->wMaxPacketSize); tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); - tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE); - ep->ep.maxpacket = desc->wMaxPacketSize; + tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE); + ep->ep.maxpacket = maxpacket; writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt); /* IN ep */ @@ -370,8 +372,8 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) /* double buffering: fifo size = 2 x max packet size */ tmp = AMD_ADDBITS( tmp, - desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT - / UDC_DWORD_BYTES, + maxpacket * UDC_EPIN_BUFF_SIZE_MULT + / UDC_DWORD_BYTES, UDC_EPIN_BUFF_SIZE); writel(tmp, &dev->ep[ep->num].regs->bufin_framenum); @@ -390,7 +392,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) /* set max packet size UDC CSR */ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); - tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, + tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT); writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); @@ -407,7 +409,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) /* set ep values */ tmp = readl(&dev->csr->ne[udc_csr_epix]); /* max packet */ - tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT); + tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT); /* ep number */ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM); /* ep direction */ @@ -2832,7 +2834,7 @@ __acquires(dev->lock) /* make usb request for gadget driver */ memset(&setup_data, 0 , sizeof(union udc_setup_data)); setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION; - setup_data.request.wValue = dev->cur_config; + setup_data.request.wValue = cpu_to_le16(dev->cur_config); /* programm the NE registers */ for (i = 0; i < UDC_EP_NUM; i++) { @@ -2881,8 +2883,8 @@ __acquires(dev->lock) memset(&setup_data, 0 , sizeof(union udc_setup_data)); setup_data.request.bRequest = USB_REQ_SET_INTERFACE; setup_data.request.bRequestType = USB_RECIP_INTERFACE; - setup_data.request.wValue = dev->cur_alt; - setup_data.request.wIndex = dev->cur_intf; + setup_data.request.wValue = cpu_to_le16(dev->cur_alt); + setup_data.request.wIndex = cpu_to_le16(dev->cur_intf); DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n", dev->cur_alt, dev->cur_intf); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 9b913afb2e6d..274c60a970cd 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -231,6 +231,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) } static const struct file_operations proc_ops = { + .owner = THIS_MODULE, .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, @@ -239,15 +240,7 @@ static const struct file_operations proc_ops = { static void create_debug_file(struct at91_udc *udc) { - struct proc_dir_entry *pde; - - pde = create_proc_entry (debug_filename, 0, NULL); - udc->pde = pde; - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = udc; + udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc); } static void remove_debug_file(struct at91_udc *udc) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 66293105d136..42036192a03c 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1555,8 +1555,7 @@ hub_descriptor (struct usb_hub_descriptor *desc) memset (desc, 0, sizeof *desc); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = (__force __u16) - (__constant_cpu_to_le16 (0x0001)); + desc->wHubCharacteristics = cpu_to_le16(0x0001); desc->bNbrPorts = 1; desc->bitmap [0] = 0xff; desc->bitmap [1] = 0xff; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index bb93bdd76593..8d61ea67a817 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -235,10 +235,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif -#ifdef CONFIG_USB_GADGET_PXA27X -#define DEV_CONFIG_CDC -#endif - #ifdef CONFIG_USB_GADGET_S3C2410 #define DEV_CONFIG_CDC #endif @@ -270,6 +266,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif +#ifdef CONFIG_USB_GADGET_PXA27X +#define DEV_CONFIG_SUBSET +#endif + #ifdef CONFIG_USB_GADGET_SUPERH #define DEV_CONFIG_SUBSET #endif diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index bf3f946fd455..47bb9f09a1aa 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2307,6 +2307,29 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg) return rc; } +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) +{ + int rc; + + DBG(fsg, "bulk-in set wedge\n"); + rc = usb_ep_set_wedge(fsg->bulk_in); + if (rc == -EAGAIN) + VDBG(fsg, "delayed bulk-in endpoint wedge\n"); + while (rc != 0) { + if (rc != -EAGAIN) { + WARN(fsg, "usb_ep_set_wedge -> %d\n", rc); + rc = 0; + break; + } + + /* Wait for a short time and then try again */ + if (msleep_interruptible(100) != 0) + return -EINTR; + rc = usb_ep_set_wedge(fsg->bulk_in); + } + return rc; +} + static int pad_with_zeros(struct fsg_dev *fsg) { struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; @@ -2957,7 +2980,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) * We aren't required to halt the OUT endpoint; instead * we can simply accept and discard any data received * until the next reset. */ - halt_bulk_in_endpoint(fsg); + wedge_bulk_in_endpoint(fsg); set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); return -EINVAL; } diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index ff3a8513e64d..7f4d4828e3aa 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -229,7 +229,7 @@ static const struct usb_ac_header_descriptor_1 ac_header_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, .bcdADC = __constant_cpu_to_le16(0x0100), - .wTotalLength = USB_DT_AC_HEADER_SIZE(1), + .wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_SIZE(1)), .bInCollection = 1, .baInterfaceNr = { [0] = GMIDI_MS_INTERFACE, @@ -253,9 +253,9 @@ static const struct usb_ms_header_descriptor ms_header_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, .bcdMSC = __constant_cpu_to_le16(0x0100), - .wTotalLength = USB_DT_MS_HEADER_SIZE + .wTotalLength = __constant_cpu_to_le16(USB_DT_MS_HEADER_SIZE + 2*USB_DT_MIDI_IN_SIZE - + 2*USB_DT_MIDI_OUT_SIZE(1), + + 2*USB_DT_MIDI_OUT_SIZE(1)), }; #define JACK_IN_EMB 1 diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 64a592cbbe7b..be6613afedbf 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -127,7 +127,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* enabling the no-toggle interrupt mode would need an api hook */ mode = 0; - max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); + max = get_unaligned_le16(&desc->wMaxPacketSize); switch (max) { case 64: mode++; case 32: mode++; diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index be0a4c1f80a2..f118f00f1466 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -485,7 +485,7 @@ struct m66592 { struct m66592_ep *epaddr2ep[16]; struct usb_request *ep0_req; /* for internal request */ - u16 ep0_data; /* for internal request */ + __le16 ep0_data; /* for internal request */ u16 old_vbus; struct timer_list timer; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 95f7662376f1..881d74c3d964 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2504,6 +2504,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) } static const struct file_operations proc_ops = { + .owner = THIS_MODULE, .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, @@ -2512,11 +2513,7 @@ static const struct file_operations proc_ops = { static void create_proc_file(void) { - struct proc_dir_entry *pde; - - pde = create_proc_entry (proc_filename, 0, NULL); - if (pde) - pde->proc_fops = &proc_ops; + proc_create(proc_filename, 0, NULL, &proc_ops); } static void remove_proc_file(void) diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c new file mode 100644 index 000000000000..75eba202f737 --- /dev/null +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -0,0 +1,2404 @@ +/* + * Handles the Intel 27x USB Device Controller (UDC) + * + * Inspired by original driver by Frank Becker, David Brownell, and others. + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/irq.h> + +#include <asm/byteorder.h> +#include <asm/hardware.h> + +#include <linux/usb.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#include <asm/arch/udc.h> + +#include "pxa27x_udc.h" + +/* + * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x + * series processors. + * + * Such controller drivers work with a gadget driver. The gadget driver + * returns descriptors, implements configuration and data protocols used + * by the host to interact with this device, and allocates endpoints to + * the different protocol interfaces. The controller driver virtualizes + * usb hardware so that the gadget drivers will be more portable. + * + * This UDC hardware wants to implement a bit too much USB protocol. The + * biggest issues are: that the endpoints have to be set up before the + * controller can be enabled (minor, and not uncommon); and each endpoint + * can only have one configuration, interface and alternative interface + * number (major, and very unusual). Once set up, these cannot be changed + * without a controller reset. + * + * The workaround is to setup all combinations necessary for the gadgets which + * will work with this driver. This is done in pxa_udc structure, statically. + * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep. + * (You could modify this if needed. Some drivers have a "fifo_mode" module + * parameter to facilitate such changes.) + * + * The combinations have been tested with these gadgets : + * - zero gadget + * - file storage gadget + * - ether gadget + * + * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is + * made of UDC's double buffering either. USB "On-The-Go" is not implemented. + * + * All the requests are handled the same way : + * - the drivers tries to handle the request directly to the IO + * - if the IO fifo is not big enough, the remaining is send/received in + * interrupt handling. + */ + +#define DRIVER_VERSION "2008-04-18" +#define DRIVER_DESC "PXA 27x USB Device Controller driver" + +static const char driver_name[] = "pxa27x_udc"; +static struct pxa_udc *the_controller; + +static void handle_ep(struct pxa_ep *ep); + +/* + * Debug filesystem + */ +#ifdef CONFIG_USB_GADGET_DEBUG_FS + +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/seq_file.h> + +static int state_dbg_show(struct seq_file *s, void *p) +{ + struct pxa_udc *udc = s->private; + int pos = 0, ret; + u32 tmp; + + ret = -ENODEV; + if (!udc->driver) + goto out; + + /* basic device status */ + pos += seq_printf(s, DRIVER_DESC "\n" + "%s version: %s\nGadget driver: %s\n", + driver_name, DRIVER_VERSION, + udc->driver ? udc->driver->driver.name : "(none)"); + + tmp = udc_readl(udc, UDCCR); + pos += seq_printf(s, + "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), " + "con=%d,inter=%d,altinter=%d\n", tmp, + (tmp & UDCCR_OEN) ? " oen":"", + (tmp & UDCCR_AALTHNP) ? " aalthnp":"", + (tmp & UDCCR_AHNP) ? " rem" : "", + (tmp & UDCCR_BHNP) ? " rstir" : "", + (tmp & UDCCR_DWRE) ? " dwre" : "", + (tmp & UDCCR_SMAC) ? " smac" : "", + (tmp & UDCCR_EMCE) ? " emce" : "", + (tmp & UDCCR_UDR) ? " udr" : "", + (tmp & UDCCR_UDA) ? " uda" : "", + (tmp & UDCCR_UDE) ? " ude" : "", + (tmp & UDCCR_ACN) >> UDCCR_ACN_S, + (tmp & UDCCR_AIN) >> UDCCR_AIN_S, + (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S); + /* registers for device and ep0 */ + pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n", + udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1)); + pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n", + udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1)); + pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR)); + pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, " + "reconfig=%lu\n", + udc->stats.irqs_reset, udc->stats.irqs_suspend, + udc->stats.irqs_resume, udc->stats.irqs_reconfig); + + ret = 0; +out: + return ret; +} + +static int queues_dbg_show(struct seq_file *s, void *p) +{ + struct pxa_udc *udc = s->private; + struct pxa_ep *ep; + struct pxa27x_request *req; + int pos = 0, i, maxpkt, ret; + + ret = -ENODEV; + if (!udc->driver) + goto out; + + /* dump endpoint queues */ + for (i = 0; i < NR_PXA_ENDPOINTS; i++) { + ep = &udc->pxa_ep[i]; + maxpkt = ep->fifo_size; + pos += seq_printf(s, "%-12s max_pkt=%d %s\n", + EPNAME(ep), maxpkt, "pio"); + + if (list_empty(&ep->queue)) { + pos += seq_printf(s, "\t(nothing queued)\n"); + continue; + } + + list_for_each_entry(req, &ep->queue, queue) { + pos += seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + } + } + + ret = 0; +out: + return ret; +} + +static int eps_dbg_show(struct seq_file *s, void *p) +{ + struct pxa_udc *udc = s->private; + struct pxa_ep *ep; + int pos = 0, i, ret; + u32 tmp; + + ret = -ENODEV; + if (!udc->driver) + goto out; + + ep = &udc->pxa_ep[0]; + tmp = udc_ep_readl(ep, UDCCSR); + pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp, + (tmp & UDCCSR0_SA) ? " sa" : "", + (tmp & UDCCSR0_RNE) ? " rne" : "", + (tmp & UDCCSR0_FST) ? " fst" : "", + (tmp & UDCCSR0_SST) ? " sst" : "", + (tmp & UDCCSR0_DME) ? " dme" : "", + (tmp & UDCCSR0_IPR) ? " ipr" : "", + (tmp & UDCCSR0_OPC) ? " opc" : ""); + for (i = 0; i < NR_PXA_ENDPOINTS; i++) { + ep = &udc->pxa_ep[i]; + tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR); + pos += seq_printf(s, "%-12s: " + "IN %lu(%lu reqs), OUT %lu(%lu reqs), " + "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, " + "udcbcr=%d\n", + EPNAME(ep), + ep->stats.in_bytes, ep->stats.in_ops, + ep->stats.out_bytes, ep->stats.out_ops, + ep->stats.irqs, + tmp, udc_ep_readl(ep, UDCCSR), + udc_ep_readl(ep, UDCBCR)); + } + + ret = 0; +out: + return ret; +} + +static int eps_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, eps_dbg_show, inode->i_private); +} + +static int queues_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, queues_dbg_show, inode->i_private); +} + +static int state_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, state_dbg_show, inode->i_private); +} + +static const struct file_operations state_dbg_fops = { + .owner = THIS_MODULE, + .open = state_dbg_open, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, +}; + +static const struct file_operations queues_dbg_fops = { + .owner = THIS_MODULE, + .open = queues_dbg_open, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, +}; + +static const struct file_operations eps_dbg_fops = { + .owner = THIS_MODULE, + .open = eps_dbg_open, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, +}; + +static void pxa_init_debugfs(struct pxa_udc *udc) +{ + struct dentry *root, *state, *queues, *eps; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + + state = debugfs_create_file("udcstate", 0400, root, udc, + &state_dbg_fops); + if (!state) + goto err_state; + queues = debugfs_create_file("queues", 0400, root, udc, + &queues_dbg_fops); + if (!queues) + goto err_queues; + eps = debugfs_create_file("epstate", 0400, root, udc, + &eps_dbg_fops); + if (!queues) + goto err_eps; + + udc->debugfs_root = root; + udc->debugfs_state = state; + udc->debugfs_queues = queues; + udc->debugfs_eps = eps; + return; +err_eps: + debugfs_remove(eps); +err_queues: + debugfs_remove(queues); +err_state: + debugfs_remove(root); +err_root: + dev_err(udc->dev, "debugfs is not available\n"); +} + +static void pxa_cleanup_debugfs(struct pxa_udc *udc) +{ + debugfs_remove(udc->debugfs_eps); + debugfs_remove(udc->debugfs_queues); + debugfs_remove(udc->debugfs_state); + debugfs_remove(udc->debugfs_root); + udc->debugfs_eps = NULL; + udc->debugfs_queues = NULL; + udc->debugfs_state = NULL; + udc->debugfs_root = NULL; +} + +#else +static inline void pxa_init_debugfs(struct pxa_udc *udc) +{ +} + +static inline void pxa_cleanup_debugfs(struct pxa_udc *udc) +{ +} +#endif + +/** + * is_match_usb_pxa - check if usb_ep and pxa_ep match + * @udc_usb_ep: usb endpoint + * @ep: pxa endpoint + * @config: configuration required in pxa_ep + * @interface: interface required in pxa_ep + * @altsetting: altsetting required in pxa_ep + * + * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise + */ +static int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep, + int config, int interface, int altsetting) +{ + if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr) + return 0; + if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in) + return 0; + if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type) + return 0; + if ((ep->config != config) || (ep->interface != interface) + || (ep->alternate != altsetting)) + return 0; + return 1; +} + +/** + * find_pxa_ep - find pxa_ep structure matching udc_usb_ep + * @udc: pxa udc + * @udc_usb_ep: udc_usb_ep structure + * + * Match udc_usb_ep and all pxa_ep available, to see if one matches. + * This is necessary because of the strong pxa hardware restriction requiring + * that once pxa endpoints are initialized, their configuration is freezed, and + * no change can be made to their address, direction, or in which configuration, + * interface or altsetting they are active ... which differs from more usual + * models which have endpoints be roughly just addressable fifos, and leave + * configuration events up to gadget drivers (like all control messages). + * + * Note that there is still a blurred point here : + * - we rely on UDCCR register "active interface" and "active altsetting". + * This is a nonsense in regard of USB spec, where multiple interfaces are + * active at the same time. + * - if we knew for sure that the pxa can handle multiple interface at the + * same time, assuming Intel's Developer Guide is wrong, this function + * should be reviewed, and a cache of couples (iface, altsetting) should + * be kept in the pxa_udc structure. In this case this function would match + * against the cache of couples instead of the "last altsetting" set up. + * + * Returns the matched pxa_ep structure or NULL if none found + */ +static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc, + struct udc_usb_ep *udc_usb_ep) +{ + int i; + struct pxa_ep *ep; + int cfg = udc->config; + int iface = udc->last_interface; + int alt = udc->last_alternate; + + if (udc_usb_ep == &udc->udc_usb_ep[0]) + return &udc->pxa_ep[0]; + + for (i = 1; i < NR_PXA_ENDPOINTS; i++) { + ep = &udc->pxa_ep[i]; + if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt)) + return ep; + } + return NULL; +} + +/** + * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep + * @udc: pxa udc + * + * Context: in_interrupt() + * + * Updates all pxa_ep fields in udc_usb_ep structures, if this field was + * previously set up (and is not NULL). The update is necessary is a + * configuration change or altsetting change was issued by the USB host. + */ +static void update_pxa_ep_matches(struct pxa_udc *udc) +{ + int i; + struct udc_usb_ep *udc_usb_ep; + + for (i = 1; i < NR_USB_ENDPOINTS; i++) { + udc_usb_ep = &udc->udc_usb_ep[i]; + if (udc_usb_ep->pxa_ep) + udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep); + } +} + +/** + * pio_irq_enable - Enables irq generation for one endpoint + * @ep: udc endpoint + */ +static void pio_irq_enable(struct pxa_ep *ep) +{ + struct pxa_udc *udc = ep->dev; + int index = EPIDX(ep); + u32 udcicr0 = udc_readl(udc, UDCICR0); + u32 udcicr1 = udc_readl(udc, UDCICR1); + + if (index < 16) + udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2))); + else + udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2))); +} + +/** + * pio_irq_disable - Disables irq generation for one endpoint + * @ep: udc endpoint + * @index: endpoint number + */ +static void pio_irq_disable(struct pxa_ep *ep) +{ + struct pxa_udc *udc = ep->dev; + int index = EPIDX(ep); + u32 udcicr0 = udc_readl(udc, UDCICR0); + u32 udcicr1 = udc_readl(udc, UDCICR1); + + if (index < 16) + udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2))); + else + udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2))); +} + +/** + * udc_set_mask_UDCCR - set bits in UDCCR + * @udc: udc device + * @mask: bits to set in UDCCR + * + * Sets bits in UDCCR, leaving DME and FST bits as they were. + */ +static inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask) +{ + u32 udccr = udc_readl(udc, UDCCR); + udc_writel(udc, UDCCR, + (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS)); +} + +/** + * udc_clear_mask_UDCCR - clears bits in UDCCR + * @udc: udc device + * @mask: bit to clear in UDCCR + * + * Clears bits in UDCCR, leaving DME and FST bits as they were. + */ +static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask) +{ + u32 udccr = udc_readl(udc, UDCCR); + udc_writel(udc, UDCCR, + (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS)); +} + +/** + * ep_count_bytes_remain - get how many bytes in udc endpoint + * @ep: udc endpoint + * + * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP) + */ +static int ep_count_bytes_remain(struct pxa_ep *ep) +{ + if (ep->dir_in) + return -EOPNOTSUPP; + return udc_ep_readl(ep, UDCBCR) & 0x3ff; +} + +/** + * ep_is_empty - checks if ep has byte ready for reading + * @ep: udc endpoint + * + * If endpoint is the control endpoint, checks if there are bytes in the + * control endpoint fifo. If endpoint is a data endpoint, checks if bytes + * are ready for reading on OUT endpoint. + * + * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint + */ +static int ep_is_empty(struct pxa_ep *ep) +{ + int ret; + + if (!is_ep0(ep) && ep->dir_in) + return -EOPNOTSUPP; + if (is_ep0(ep)) + ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE); + else + ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE); + return ret; +} + +/** + * ep_is_full - checks if ep has place to write bytes + * @ep: udc endpoint + * + * If endpoint is not the control endpoint and is an IN endpoint, checks if + * there is place to write bytes into the endpoint. + * + * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint + */ +static int ep_is_full(struct pxa_ep *ep) +{ + if (is_ep0(ep)) + return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR); + if (!ep->dir_in) + return -EOPNOTSUPP; + return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF)); +} + +/** + * epout_has_pkt - checks if OUT endpoint fifo has a packet available + * @ep: pxa endpoint + * + * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep. + */ +static int epout_has_pkt(struct pxa_ep *ep) +{ + if (!is_ep0(ep) && ep->dir_in) + return -EOPNOTSUPP; + if (is_ep0(ep)) + return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC); + return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC); +} + +/** + * set_ep0state - Set ep0 automata state + * @dev: udc device + * @state: state + */ +static void set_ep0state(struct pxa_udc *udc, int state) +{ + struct pxa_ep *ep = &udc->pxa_ep[0]; + char *old_stname = EP0_STNAME(udc); + + udc->ep0state = state; + ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname, + EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR), + udc_ep_readl(ep, UDCBCR)); +} + +/** + * ep0_idle - Put control endpoint into idle state + * @dev: udc device + */ +static void ep0_idle(struct pxa_udc *dev) +{ + set_ep0state(dev, WAIT_FOR_SETUP); +} + +/** + * inc_ep_stats_reqs - Update ep stats counts + * @ep: physical endpoint + * @req: usb request + * @is_in: ep direction (USB_DIR_IN or 0) + * + */ +static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in) +{ + if (is_in) + ep->stats.in_ops++; + else + ep->stats.out_ops++; +} + +/** + * inc_ep_stats_bytes - Update ep stats counts + * @ep: physical endpoint + * @count: bytes transfered on endpoint + * @req: usb request + * @is_in: ep direction (USB_DIR_IN or 0) + */ +static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in) +{ + if (is_in) + ep->stats.in_bytes += count; + else + ep->stats.out_bytes += count; +} + +/** + * pxa_ep_setup - Sets up an usb physical endpoint + * @ep: pxa27x physical endpoint + * + * Find the physical pxa27x ep, and setup its UDCCR + */ +static __init void pxa_ep_setup(struct pxa_ep *ep) +{ + u32 new_udccr; + + new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN) + | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN) + | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN) + | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN) + | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET) + | ((ep->dir_in) ? UDCCONR_ED : 0) + | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS) + | UDCCONR_EE; + + udc_ep_writel(ep, UDCCR, new_udccr); +} + +/** + * pxa_eps_setup - Sets up all usb physical endpoints + * @dev: udc device + * + * Setup all pxa physical endpoints, except ep0 + */ +static __init void pxa_eps_setup(struct pxa_udc *dev) +{ + unsigned int i; + + dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev); + + for (i = 1; i < NR_PXA_ENDPOINTS; i++) + pxa_ep_setup(&dev->pxa_ep[i]); +} + +/** + * pxa_ep_alloc_request - Allocate usb request + * @_ep: usb endpoint + * @gfp_flags: + * + * For the pxa27x, these can just wrap kmalloc/kfree. gadget drivers + * must still pass correctly initialized endpoints, since other controller + * drivers may care about how it's currently set up (dma issues etc). + */ +static struct usb_request * +pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct pxa27x_request *req; + + req = kzalloc(sizeof *req, gfp_flags); + if (!req || !_ep) + return NULL; + + INIT_LIST_HEAD(&req->queue); + req->in_use = 0; + req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + + return &req->req; +} + +/** + * pxa_ep_free_request - Free usb request + * @_ep: usb endpoint + * @_req: usb request + * + * Wrapper around kfree to free _req + */ +static void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct pxa27x_request *req; + + req = container_of(_req, struct pxa27x_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + +/** + * ep_add_request - add a request to the endpoint's queue + * @ep: usb endpoint + * @req: usb request + * + * Context: ep->lock held + * + * Queues the request in the endpoint's queue, and enables the interrupts + * on the endpoint. + */ +static void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req) +{ + if (unlikely(!req)) + return; + ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req, + req->req.length, udc_ep_readl(ep, UDCCSR)); + + req->in_use = 1; + list_add_tail(&req->queue, &ep->queue); + pio_irq_enable(ep); +} + +/** + * ep_del_request - removes a request from the endpoint's queue + * @ep: usb endpoint + * @req: usb request + * + * Context: ep->lock held + * + * Unqueue the request from the endpoint's queue. If there are no more requests + * on the endpoint, and if it's not the control endpoint, interrupts are + * disabled on the endpoint. + */ +static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req) +{ + if (unlikely(!req)) + return; + ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req, + req->req.length, udc_ep_readl(ep, UDCCSR)); + + list_del_init(&req->queue); + req->in_use = 0; + if (!is_ep0(ep) && list_empty(&ep->queue)) + pio_irq_disable(ep); +} + +/** + * req_done - Complete an usb request + * @ep: pxa physical endpoint + * @req: pxa request + * @status: usb request status sent to gadget API + * + * Context: ep->lock held + * + * Retire a pxa27x usb request. Endpoint must be locked. + */ +static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status) +{ + ep_del_request(ep, req); + if (likely(req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + ep_dbg(ep, "complete req %p stat %d len %u/%u\n", + &req->req, status, + req->req.actual, req->req.length); + + req->req.complete(&req->udc_usb_ep->usb_ep, &req->req); +} + +/** + * ep_end_out_req - Ends control endpoint in request + * @ep: physical endpoint + * @req: pxa request + * + * Context: ep->lock held + * + * Ends endpoint in request (completes usb request). + */ +static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) +{ + inc_ep_stats_reqs(ep, !USB_DIR_IN); + req_done(ep, req, 0); +} + +/** + * ep0_end_out_req - Ends control endpoint in request (ends data stage) + * @ep: physical endpoint + * @req: pxa request + * + * Context: ep->lock held + * + * Ends control endpoint in request (completes usb request), and puts + * control endpoint into idle state + */ +static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) +{ + set_ep0state(ep->dev, OUT_STATUS_STAGE); + ep_end_out_req(ep, req); + ep0_idle(ep->dev); +} + +/** + * ep_end_in_req - Ends endpoint out request + * @ep: physical endpoint + * @req: pxa request + * + * Context: ep->lock held + * + * Ends endpoint out request (completes usb request). + */ +static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) +{ + inc_ep_stats_reqs(ep, USB_DIR_IN); + req_done(ep, req, 0); +} + +/** + * ep0_end_in_req - Ends control endpoint out request (ends data stage) + * @ep: physical endpoint + * @req: pxa request + * + * Context: ep->lock held + * + * Ends control endpoint out request (completes usb request), and puts + * control endpoint into status state + */ +static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) +{ + struct pxa_udc *udc = ep->dev; + + set_ep0state(udc, IN_STATUS_STAGE); + ep_end_in_req(ep, req); +} + +/** + * nuke - Dequeue all requests + * @ep: pxa endpoint + * @status: usb request status + * + * Context: ep->lock held + * + * Dequeues all requests on an endpoint. As a side effect, interrupts will be + * disabled on that endpoint (because no more requests). + */ +static void nuke(struct pxa_ep *ep, int status) +{ + struct pxa27x_request *req; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + req_done(ep, req, status); + } +} + +/** + * read_packet - transfer 1 packet from an OUT endpoint into request + * @ep: pxa physical endpoint + * @req: usb request + * + * Takes bytes from OUT endpoint and transfers them info the usb request. + * If there is less space in request than bytes received in OUT endpoint, + * bytes are left in the OUT endpoint. + * + * Returns how many bytes were actually transfered + */ +static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req) +{ + u32 *buf; + int bytes_ep, bufferspace, count, i; + + bytes_ep = ep_count_bytes_remain(ep); + bufferspace = req->req.length - req->req.actual; + + buf = (u32 *)(req->req.buf + req->req.actual); + prefetchw(buf); + + if (likely(!ep_is_empty(ep))) + count = min(bytes_ep, bufferspace); + else /* zlp */ + count = 0; + + for (i = count; i > 0; i -= 4) + *buf++ = udc_ep_readl(ep, UDCDR); + req->req.actual += count; + + udc_ep_writel(ep, UDCCSR, UDCCSR_PC); + + return count; +} + +/** + * write_packet - transfer 1 packet from request into an IN endpoint + * @ep: pxa physical endpoint + * @req: usb request + * @max: max bytes that fit into endpoint + * + * Takes bytes from usb request, and transfers them into the physical + * endpoint. If there are no bytes to transfer, doesn't write anything + * to physical endpoint. + * + * Returns how many bytes were actually transfered. + */ +static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req, + unsigned int max) +{ + int length, count, remain, i; + u32 *buf; + u8 *buf_8; + + buf = (u32 *)(req->req.buf + req->req.actual); + prefetch(buf); + + length = min(req->req.length - req->req.actual, max); + req->req.actual += length; + + remain = length & 0x3; + count = length & ~(0x3); + for (i = count; i > 0 ; i -= 4) + udc_ep_writel(ep, UDCDR, *buf++); + + buf_8 = (u8 *)buf; + for (i = remain; i > 0; i--) + udc_ep_writeb(ep, UDCDR, *buf_8++); + + ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain, + udc_ep_readl(ep, UDCCSR)); + + return length; +} + +/** + * read_fifo - Transfer packets from OUT endpoint into usb request + * @ep: pxa physical endpoint + * @req: usb request + * + * Context: callable when in_interrupt() + * + * Unload as many packets as possible from the fifo we use for usb OUT + * transfers and put them into the request. Caller should have made sure + * there's at least one packet ready. + * Doesn't complete the request, that's the caller's job + * + * Returns 1 if the request completed, 0 otherwise + */ +static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req) +{ + int count, is_short, completed = 0; + + while (epout_has_pkt(ep)) { + count = read_packet(ep, req); + inc_ep_stats_bytes(ep, count, !USB_DIR_IN); + + is_short = (count < ep->fifo_size); + ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n", + udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "", + &req->req, req->req.actual, req->req.length); + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + completed = 1; + break; + } + /* finished that packet. the next one may be waiting... */ + } + return completed; +} + +/** + * write_fifo - transfer packets from usb request into an IN endpoint + * @ep: pxa physical endpoint + * @req: pxa usb request + * + * Write to an IN endpoint fifo, as many packets as possible. + * irqs will use this to write the rest later. + * caller guarantees at least one packet buffer is ready (or a zlp). + * Doesn't complete the request, that's the caller's job + * + * Returns 1 if request fully transfered, 0 if partial transfer + */ +static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req) +{ + unsigned max; + int count, is_short, is_last = 0, completed = 0, totcount = 0; + u32 udccsr; + + max = ep->fifo_size; + do { + is_short = 0; + + udccsr = udc_ep_readl(ep, UDCCSR); + if (udccsr & UDCCSR_PC) { + ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n", + udccsr); + udc_ep_writel(ep, UDCCSR, UDCCSR_PC); + } + if (udccsr & UDCCSR_TRN) { + ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n", + udccsr); + udc_ep_writel(ep, UDCCSR, UDCCSR_TRN); + } + + count = write_packet(ep, req, max); + inc_ep_stats_bytes(ep, count, USB_DIR_IN); + totcount += count; + + /* last packet is usually short (or a zlp) */ + if (unlikely(count < max)) { + is_last = 1; + is_short = 1; + } else { + if (likely(req->req.length > req->req.actual) + || req->req.zero) + is_last = 0; + else + is_last = 1; + /* interrupt/iso maxpacket may not fill the fifo */ + is_short = unlikely(max < ep->fifo_size); + } + + if (is_short) + udc_ep_writel(ep, UDCCSR, UDCCSR_SP); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + completed = 1; + break; + } + } while (!ep_is_full(ep)); + + ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n", + totcount, is_last ? "/L" : "", is_short ? "/S" : "", + req->req.length - req->req.actual, &req->req); + + return completed; +} + +/** + * read_ep0_fifo - Transfer packets from control endpoint into usb request + * @ep: control endpoint + * @req: pxa usb request + * + * Special ep0 version of the above read_fifo. Reads as many bytes from control + * endpoint as can be read, and stores them into usb request (limited by request + * maximum length). + * + * Returns 0 if usb request only partially filled, 1 if fully filled + */ +static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) +{ + int count, is_short, completed = 0; + + while (epout_has_pkt(ep)) { + count = read_packet(ep, req); + udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC); + inc_ep_stats_bytes(ep, count, !USB_DIR_IN); + + is_short = (count < ep->fifo_size); + ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n", + udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "", + &req->req, req->req.actual, req->req.length); + + if (is_short || req->req.actual >= req->req.length) { + completed = 1; + break; + } + } + + return completed; +} + +/** + * write_ep0_fifo - Send a request to control endpoint (ep0 in) + * @ep: control endpoint + * @req: request + * + * Context: callable when in_interrupt() + * + * Sends a request (or a part of the request) to the control endpoint (ep0 in). + * If the request doesn't fit, the remaining part will be sent from irq. + * The request is considered fully written only if either : + * - last write transfered all remaining bytes, but fifo was not fully filled + * - last write was a 0 length write + * + * Returns 1 if request fully written, 0 if request only partially sent + */ +static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) +{ + unsigned count; + int is_last, is_short; + + count = write_packet(ep, req, EP0_FIFO_SIZE); + inc_ep_stats_bytes(ep, count, USB_DIR_IN); + + is_short = (count < EP0_FIFO_SIZE); + is_last = ((count == 0) || (count < EP0_FIFO_SIZE)); + + /* Sends either a short packet or a 0 length packet */ + if (unlikely(is_short)) + udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR); + + ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n", + count, is_short ? "/S" : "", is_last ? "/L" : "", + req->req.length - req->req.actual, + &req->req, udc_ep_readl(ep, UDCCSR)); + + return is_last; +} + +/** + * pxa_ep_queue - Queue a request into an IN endpoint + * @_ep: usb endpoint + * @_req: usb request + * @gfp_flags: flags + * + * Context: normally called when !in_interrupt, but callable when in_interrupt() + * in the special case of ep0 setup : + * (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue) + * + * Returns 0 if succedeed, error otherwise + */ +static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct udc_usb_ep *udc_usb_ep; + struct pxa_ep *ep; + struct pxa27x_request *req; + struct pxa_udc *dev; + unsigned long flags; + int rc = 0; + int is_first_req; + unsigned length; + + req = container_of(_req, struct pxa27x_request, req); + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + + if (unlikely(!_req || !_req->complete || !_req->buf)) + return -EINVAL; + + if (unlikely(!_ep)) + return -EINVAL; + + dev = udc_usb_ep->dev; + ep = udc_usb_ep->pxa_ep; + if (unlikely(!ep)) + return -EINVAL; + + dev = ep->dev; + if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + ep_dbg(ep, "bogus device state\n"); + return -ESHUTDOWN; + } + + /* iso is always one packet per request, that's the only way + * we can report per-packet status. that also helps with dma. + */ + if (unlikely(EPXFERTYPE_is_ISO(ep) + && req->req.length > ep->fifo_size)) + return -EMSGSIZE; + + spin_lock_irqsave(&ep->lock, flags); + + is_first_req = list_empty(&ep->queue); + ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n", + _req, is_first_req ? "yes" : "no", + _req->length, _req->buf); + + if (!ep->enabled) { + _req->status = -ESHUTDOWN; + rc = -ESHUTDOWN; + goto out; + } + + if (req->in_use) { + ep_err(ep, "refusing to queue req %p (already queued)\n", req); + goto out; + } + + length = _req->length; + _req->status = -EINPROGRESS; + _req->actual = 0; + + ep_add_request(ep, req); + + if (is_ep0(ep)) { + switch (dev->ep0state) { + case WAIT_ACK_SET_CONF_INTERF: + if (length == 0) { + ep_end_in_req(ep, req); + } else { + ep_err(ep, "got a request of %d bytes while" + "in state WATI_ACK_SET_CONF_INTERF\n", + length); + ep_del_request(ep, req); + rc = -EL2HLT; + } + ep0_idle(ep->dev); + break; + case IN_DATA_STAGE: + if (!ep_is_full(ep)) + if (write_ep0_fifo(ep, req)) + ep0_end_in_req(ep, req); + break; + case OUT_DATA_STAGE: + if ((length == 0) || !epout_has_pkt(ep)) + if (read_ep0_fifo(ep, req)) + ep0_end_out_req(ep, req); + break; + default: + ep_err(ep, "odd state %s to send me a request\n", + EP0_STNAME(ep->dev)); + ep_del_request(ep, req); + rc = -EL2HLT; + break; + } + } else { + handle_ep(ep); + } + +out: + spin_unlock_irqrestore(&ep->lock, flags); + return rc; +} + +/** + * pxa_ep_dequeue - Dequeue one request + * @_ep: usb endpoint + * @_req: usb request + * + * Return 0 if no error, -EINVAL or -ECONNRESET otherwise + */ +static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct pxa_ep *ep; + struct udc_usb_ep *udc_usb_ep; + struct pxa27x_request *req; + unsigned long flags; + int rc; + + if (!_ep) + return -EINVAL; + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + ep = udc_usb_ep->pxa_ep; + if (!ep || is_ep0(ep)) + return -EINVAL; + + spin_lock_irqsave(&ep->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + + rc = -EINVAL; + if (&req->req != _req) + goto out; + + rc = 0; + req_done(ep, req, -ECONNRESET); +out: + spin_unlock_irqrestore(&ep->lock, flags); + return rc; +} + +/** + * pxa_ep_set_halt - Halts operations on one endpoint + * @_ep: usb endpoint + * @value: + * + * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise + */ +static int pxa_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct pxa_ep *ep; + struct udc_usb_ep *udc_usb_ep; + unsigned long flags; + int rc; + + + if (!_ep) + return -EINVAL; + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + ep = udc_usb_ep->pxa_ep; + if (!ep || is_ep0(ep)) + return -EINVAL; + + if (value == 0) { + /* + * This path (reset toggle+halt) is needed to implement + * SET_INTERFACE on normal hardware. but it can't be + * done from software on the PXA UDC, and the hardware + * forgets to do it as part of SET_INTERFACE automagic. + */ + ep_dbg(ep, "only host can clear halt\n"); + return -EROFS; + } + + spin_lock_irqsave(&ep->lock, flags); + + rc = -EAGAIN; + if (ep->dir_in && (ep_is_full(ep) || !list_empty(&ep->queue))) + goto out; + + /* FST, FEF bits are the same for control and non control endpoints */ + rc = 0; + udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF); + if (is_ep0(ep)) + set_ep0state(ep->dev, STALL); + +out: + spin_unlock_irqrestore(&ep->lock, flags); + return rc; +} + +/** + * pxa_ep_fifo_status - Get how many bytes in physical endpoint + * @_ep: usb endpoint + * + * Returns number of bytes in OUT fifos. Broken for IN fifos. + */ +static int pxa_ep_fifo_status(struct usb_ep *_ep) +{ + struct pxa_ep *ep; + struct udc_usb_ep *udc_usb_ep; + + if (!_ep) + return -ENODEV; + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + ep = udc_usb_ep->pxa_ep; + if (!ep || is_ep0(ep)) + return -ENODEV; + + if (ep->dir_in) + return -EOPNOTSUPP; + if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep)) + return 0; + else + return ep_count_bytes_remain(ep) + 1; +} + +/** + * pxa_ep_fifo_flush - Flushes one endpoint + * @_ep: usb endpoint + * + * Discards all data in one endpoint(IN or OUT), except control endpoint. + */ +static void pxa_ep_fifo_flush(struct usb_ep *_ep) +{ + struct pxa_ep *ep; + struct udc_usb_ep *udc_usb_ep; + unsigned long flags; + + if (!_ep) + return; + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + ep = udc_usb_ep->pxa_ep; + if (!ep || is_ep0(ep)) + return; + + spin_lock_irqsave(&ep->lock, flags); + + if (unlikely(!list_empty(&ep->queue))) + ep_dbg(ep, "called while queue list not empty\n"); + ep_dbg(ep, "called\n"); + + /* for OUT, just read and discard the FIFO contents. */ + if (!ep->dir_in) { + while (!ep_is_empty(ep)) + udc_ep_readl(ep, UDCDR); + } else { + /* most IN status is the same, but ISO can't stall */ + udc_ep_writel(ep, UDCCSR, + UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN + | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST)); + } + + spin_unlock_irqrestore(&ep->lock, flags); + + return; +} + +/** + * pxa_ep_enable - Enables usb endpoint + * @_ep: usb endpoint + * @desc: usb endpoint descriptor + * + * Nothing much to do here, as ep configuration is done once and for all + * before udc is enabled. After udc enable, no physical endpoint configuration + * can be changed. + * Function makes sanity checks and flushes the endpoint. + */ +static int pxa_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct pxa_ep *ep; + struct udc_usb_ep *udc_usb_ep; + struct pxa_udc *udc; + + if (!_ep || !desc) + return -EINVAL; + + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + if (udc_usb_ep->pxa_ep) { + ep = udc_usb_ep->pxa_ep; + ep_warn(ep, "usb_ep %s already enabled, doing nothing\n", + _ep->name); + } else { + ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep); + } + + if (!ep || is_ep0(ep)) { + dev_err(udc_usb_ep->dev->dev, + "unable to match pxa_ep for ep %s\n", + _ep->name); + return -EINVAL; + } + + if ((desc->bDescriptorType != USB_DT_ENDPOINT) + || (ep->type != usb_endpoint_type(desc))) { + ep_err(ep, "type mismatch\n"); + return -EINVAL; + } + + if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { + ep_err(ep, "bad maxpacket\n"); + return -ERANGE; + } + + udc_usb_ep->pxa_ep = ep; + udc = ep->dev; + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { + ep_err(ep, "bogus device state\n"); + return -ESHUTDOWN; + } + + ep->enabled = 1; + + /* flush fifo (mostly for OUT buffers) */ + pxa_ep_fifo_flush(_ep); + + ep_dbg(ep, "enabled\n"); + return 0; +} + +/** + * pxa_ep_disable - Disable usb endpoint + * @_ep: usb endpoint + * + * Same as for pxa_ep_enable, no physical endpoint configuration can be + * changed. + * Function flushes the endpoint and related requests. + */ +static int pxa_ep_disable(struct usb_ep *_ep) +{ + struct pxa_ep *ep; + struct udc_usb_ep *udc_usb_ep; + unsigned long flags; + + if (!_ep) + return -EINVAL; + + udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); + ep = udc_usb_ep->pxa_ep; + if (!ep || is_ep0(ep) || !list_empty(&ep->queue)) + return -EINVAL; + + spin_lock_irqsave(&ep->lock, flags); + ep->enabled = 0; + nuke(ep, -ESHUTDOWN); + spin_unlock_irqrestore(&ep->lock, flags); + + pxa_ep_fifo_flush(_ep); + udc_usb_ep->pxa_ep = NULL; + + ep_dbg(ep, "disabled\n"); + return 0; +} + +static struct usb_ep_ops pxa_ep_ops = { + .enable = pxa_ep_enable, + .disable = pxa_ep_disable, + + .alloc_request = pxa_ep_alloc_request, + .free_request = pxa_ep_free_request, + + .queue = pxa_ep_queue, + .dequeue = pxa_ep_dequeue, + + .set_halt = pxa_ep_set_halt, + .fifo_status = pxa_ep_fifo_status, + .fifo_flush = pxa_ep_fifo_flush, +}; + + +/** + * pxa_udc_get_frame - Returns usb frame number + * @_gadget: usb gadget + */ +static int pxa_udc_get_frame(struct usb_gadget *_gadget) +{ + struct pxa_udc *udc = to_gadget_udc(_gadget); + + return (udc_readl(udc, UDCFNR) & 0x7ff); +} + +/** + * pxa_udc_wakeup - Force udc device out of suspend + * @_gadget: usb gadget + * + * Returns 0 if succesfull, error code otherwise + */ +static int pxa_udc_wakeup(struct usb_gadget *_gadget) +{ + struct pxa_udc *udc = to_gadget_udc(_gadget); + + /* host may not have enabled remote wakeup */ + if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0) + return -EHOSTUNREACH; + udc_set_mask_UDCCR(udc, UDCCR_UDR); + return 0; +} + +static const struct usb_gadget_ops pxa_udc_ops = { + .get_frame = pxa_udc_get_frame, + .wakeup = pxa_udc_wakeup, + /* current versions must always be self-powered */ +}; + +/** + * udc_disable - disable udc device controller + * @udc: udc device + * + * Disables the udc device : disables clocks, udc interrupts, control endpoint + * interrupts. + */ +static void udc_disable(struct pxa_udc *udc) +{ + udc_writel(udc, UDCICR0, 0); + udc_writel(udc, UDCICR1, 0); + + udc_clear_mask_UDCCR(udc, UDCCR_UDE); + clk_disable(udc->clk); + + ep0_idle(udc); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); +} + +/** + * udc_init_data - Initialize udc device data structures + * @dev: udc device + * + * Initializes gadget endpoint list, endpoints locks. No action is taken + * on the hardware. + */ +static __init void udc_init_data(struct pxa_udc *dev) +{ + int i; + struct pxa_ep *ep; + + /* device/ep0 records init */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0]; + ep0_idle(dev); + strcpy(dev->dev->bus_id, ""); + + /* PXA endpoints init */ + for (i = 0; i < NR_PXA_ENDPOINTS; i++) { + ep = &dev->pxa_ep[i]; + + ep->enabled = is_ep0(ep); + INIT_LIST_HEAD(&ep->queue); + spin_lock_init(&ep->lock); + } + + /* USB endpoints init */ + for (i = 0; i < NR_USB_ENDPOINTS; i++) + if (i != 0) + list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list, + &dev->gadget.ep_list); +} + +/** + * udc_enable - Enables the udc device + * @dev: udc device + * + * Enables the udc device : enables clocks, udc interrupts, control endpoint + * interrupts, sets usb as UDC client and setups endpoints. + */ +static void udc_enable(struct pxa_udc *udc) +{ + udc_writel(udc, UDCICR0, 0); + udc_writel(udc, UDCICR1, 0); + udc_writel(udc, UP2OCR, UP2OCR_HXOE); + udc_clear_mask_UDCCR(udc, UDCCR_UDE); + + clk_enable(udc->clk); + + ep0_idle(udc); + udc->gadget.speed = USB_SPEED_FULL; + memset(&udc->stats, 0, sizeof(udc->stats)); + + udc_set_mask_UDCCR(udc, UDCCR_UDE); + udelay(2); + if (udc_readl(udc, UDCCR) & UDCCR_EMCE) + dev_err(udc->dev, "Configuration errors, udc disabled\n"); + + /* + * Caller must be able to sleep in order to cope with startup transients + */ + msleep(100); + + /* enable suspend/resume and reset irqs */ + udc_writel(udc, UDCICR1, + UDCICR1_IECC | UDCICR1_IERU + | UDCICR1_IESU | UDCICR1_IERS); + + /* enable ep0 irqs */ + pio_irq_enable(&udc->pxa_ep[0]); + + dev_info(udc->dev, "UDC connecting\n"); + if (udc->mach->udc_command) + udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); +} + +/** + * usb_gadget_register_driver - Register gadget driver + * @driver: gadget driver + * + * When a driver is successfully registered, it will receive control requests + * including set_configuration(), which enables non-control requests. Then + * usb traffic follows until a disconnect is reported. Then a host may connect + * again, or the driver might get unbound. + * + * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise + */ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct pxa_udc *udc = the_controller; + int retval; + + if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind + || !driver->disconnect || !driver->setup) + return -EINVAL; + if (!udc) + return -ENODEV; + if (udc->driver) + return -EBUSY; + + /* first hook up the driver ... */ + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + + retval = device_add(&udc->gadget.dev); + if (retval) { + dev_err(udc->dev, "device_add error %d\n", retval); + goto add_fail; + } + retval = driver->bind(&udc->gadget); + if (retval) { + dev_err(udc->dev, "bind to driver %s --> error %d\n", + driver->driver.name, retval); + goto bind_fail; + } + dev_dbg(udc->dev, "registered gadget driver '%s'\n", + driver->driver.name); + + udc_enable(udc); + return 0; + +bind_fail: + device_del(&udc->gadget.dev); +add_fail: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return retval; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + + +/** + * stop_activity - Stops udc endpoints + * @udc: udc device + * @driver: gadget driver + * + * Disables all udc endpoints (even control endpoint), report disconnect to + * the gadget user. + */ +static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect drivers more than once */ + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + udc->gadget.speed = USB_SPEED_UNKNOWN; + + for (i = 0; i < NR_USB_ENDPOINTS; i++) + pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep); + + if (driver) + driver->disconnect(&udc->gadget); +} + +/** + * usb_gadget_unregister_driver - Unregister the gadget driver + * @driver: gadget driver + * + * Returns 0 if no error, -ENODEV, -EINVAL otherwise + */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct pxa_udc *udc = the_controller; + + if (!udc) + return -ENODEV; + if (!driver || driver != udc->driver || !driver->unbind) + return -EINVAL; + + stop_activity(udc, driver); + udc_disable(udc); + + driver->unbind(&udc->gadget); + udc->driver = NULL; + + device_del(&udc->gadget.dev); + + dev_info(udc->dev, "unregistered gadget driver '%s'\n", + driver->driver.name); + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/** + * handle_ep0_ctrl_req - handle control endpoint control request + * @udc: udc device + * @req: control request + */ +static void handle_ep0_ctrl_req(struct pxa_udc *udc, + struct pxa27x_request *req) +{ + struct pxa_ep *ep = &udc->pxa_ep[0]; + union { + struct usb_ctrlrequest r; + u32 word[2]; + } u; + int i; + int have_extrabytes = 0; + + nuke(ep, -EPROTO); + + /* read SETUP packet */ + for (i = 0; i < 2; i++) { + if (unlikely(ep_is_empty(ep))) + goto stall; + u.word[i] = udc_ep_readl(ep, UDCDR); + } + + have_extrabytes = !ep_is_empty(ep); + while (!ep_is_empty(ep)) { + i = udc_ep_readl(ep, UDCDR); + ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i); + } + + le16_to_cpus(&u.r.wValue); + le16_to_cpus(&u.r.wIndex); + le16_to_cpus(&u.r.wLength); + + ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, u.r.wLength); + if (unlikely(have_extrabytes)) + goto stall; + + if (u.r.bRequestType & USB_DIR_IN) + set_ep0state(udc, IN_DATA_STAGE); + else + set_ep0state(udc, OUT_DATA_STAGE); + + /* Tell UDC to enter Data Stage */ + udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC); + + i = udc->driver->setup(&udc->gadget, &u.r); + if (i < 0) + goto stall; +out: + return; +stall: + ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n", + udc_ep_readl(ep, UDCCSR), i); + udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF); + set_ep0state(udc, STALL); + goto out; +} + +/** + * handle_ep0 - Handle control endpoint data transfers + * @udc: udc device + * @fifo_irq: 1 if triggered by fifo service type irq + * @opc_irq: 1 if triggered by output packet complete type irq + * + * Context : when in_interrupt() or with ep->lock held + * + * Tries to transfer all pending request data into the endpoint and/or + * transfer all pending data in the endpoint into usb requests. + * Handles states of ep0 automata. + * + * PXA27x hardware handles several standard usb control requests without + * driver notification. The requests fully handled by hardware are : + * SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE, + * GET_STATUS + * The requests handled by hardware, but with irq notification are : + * SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE + * The remaining standard requests really handled by handle_ep0 are : + * GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests. + * Requests standardized outside of USB 2.0 chapter 9 are handled more + * uniformly, by gadget drivers. + * + * The control endpoint state machine is _not_ USB spec compliant, it's even + * hardly compliant with Intel PXA270 developers guide. + * The key points which inferred this state machine are : + * - on every setup token, bit UDCCSR0_SA is raised and held until cleared by + * software. + * - on every OUT packet received, UDCCSR0_OPC is raised and held until + * cleared by software. + * - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it + * before reading ep0. + * - irq can be called on a "packet complete" event (opc_irq=1), while + * UDCCSR0_OPC is not yet raised (delta can be as big as 100ms + * from experimentation). + * - as UDCCSR0_SA can be activated while in irq handling, and clearing + * UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC + * => we never actually read the "status stage" packet of an IN data stage + * => this is not documented in Intel documentation + * - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA + * STAGE. The driver add STATUS STAGE to send last zero length packet in + * OUT_STATUS_STAGE. + * - special attention was needed for IN_STATUS_STAGE. If a packet complete + * event is detected, we terminate the status stage without ackowledging the + * packet (not to risk to loose a potential SETUP packet) + */ +static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) +{ + u32 udccsr0; + struct pxa_ep *ep = &udc->pxa_ep[0]; + struct pxa27x_request *req = NULL; + int completed = 0; + + udccsr0 = udc_ep_readl(ep, UDCCSR); + ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n", + EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR), + (fifo_irq << 1 | opc_irq)); + + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + + if (udccsr0 & UDCCSR0_SST) { + ep_dbg(ep, "clearing stall status\n"); + nuke(ep, -EPIPE); + udc_ep_writel(ep, UDCCSR, UDCCSR0_SST); + ep0_idle(udc); + } + + if (udccsr0 & UDCCSR0_SA) { + nuke(ep, 0); + set_ep0state(udc, SETUP_STAGE); + } + + switch (udc->ep0state) { + case WAIT_FOR_SETUP: + /* + * Hardware bug : beware, we cannot clear OPC, since we would + * miss a potential OPC irq for a setup packet. + * So, we only do ... nothing, and hope for a next irq with + * UDCCSR0_SA set. + */ + break; + case SETUP_STAGE: + udccsr0 &= UDCCSR0_CTRL_REQ_MASK; + if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK)) + handle_ep0_ctrl_req(udc, req); + break; + case IN_DATA_STAGE: /* GET_DESCRIPTOR */ + if (epout_has_pkt(ep)) + udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC); + if (req && !ep_is_full(ep)) + completed = write_ep0_fifo(ep, req); + if (completed) + ep0_end_in_req(ep, req); + break; + case OUT_DATA_STAGE: /* SET_DESCRIPTOR */ + if (epout_has_pkt(ep) && req) + completed = read_ep0_fifo(ep, req); + if (completed) + ep0_end_out_req(ep, req); + break; + case STALL: + udc_ep_writel(ep, UDCCSR, UDCCSR0_FST); + break; + case IN_STATUS_STAGE: + /* + * Hardware bug : beware, we cannot clear OPC, since we would + * miss a potential PC irq for a setup packet. + * So, we only put the ep0 into WAIT_FOR_SETUP state. + */ + if (opc_irq) + ep0_idle(udc); + break; + case OUT_STATUS_STAGE: + case WAIT_ACK_SET_CONF_INTERF: + ep_warn(ep, "should never get in %s state here!!!\n", + EP0_STNAME(ep->dev)); + ep0_idle(udc); + break; + } +} + +/** + * handle_ep - Handle endpoint data tranfers + * @ep: pxa physical endpoint + * + * Tries to transfer all pending request data into the endpoint and/or + * transfer all pending data in the endpoint into usb requests. + * + * Is always called when in_interrupt() or with ep->lock held. + */ +static void handle_ep(struct pxa_ep *ep) +{ + struct pxa27x_request *req; + int completed; + u32 udccsr; + int is_in = ep->dir_in; + int loop = 0; + + do { + completed = 0; + udccsr = udc_ep_readl(ep, UDCCSR); + if (likely(!list_empty(&ep->queue))) + req = list_entry(ep->queue.next, + struct pxa27x_request, queue); + else + req = NULL; + + ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n", + req, udccsr, loop++); + + if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN))) + udc_ep_writel(ep, UDCCSR, + udccsr & (UDCCSR_SST | UDCCSR_TRN)); + if (!req) + break; + + if (unlikely(is_in)) { + if (likely(!ep_is_full(ep))) + completed = write_fifo(ep, req); + if (completed) + ep_end_in_req(ep, req); + } else { + if (likely(epout_has_pkt(ep))) + completed = read_fifo(ep, req); + if (completed) + ep_end_out_req(ep, req); + } + } while (completed); +} + +/** + * pxa27x_change_configuration - Handle SET_CONF usb request notification + * @udc: udc device + * @config: usb configuration + * + * Post the request to upper level. + * Don't use any pxa specific harware configuration capabilities + */ +static void pxa27x_change_configuration(struct pxa_udc *udc, int config) +{ + struct usb_ctrlrequest req ; + + dev_dbg(udc->dev, "config=%d\n", config); + + udc->config = config; + udc->last_interface = 0; + udc->last_alternate = 0; + + req.bRequestType = 0; + req.bRequest = USB_REQ_SET_CONFIGURATION; + req.wValue = config; + req.wIndex = 0; + req.wLength = 0; + + set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); + udc->driver->setup(&udc->gadget, &req); +} + +/** + * pxa27x_change_interface - Handle SET_INTERF usb request notification + * @udc: udc device + * @iface: interface number + * @alt: alternate setting number + * + * Post the request to upper level. + * Don't use any pxa specific harware configuration capabilities + */ +static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt) +{ + struct usb_ctrlrequest req; + + dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt); + + udc->last_interface = iface; + udc->last_alternate = alt; + + req.bRequestType = USB_RECIP_INTERFACE; + req.bRequest = USB_REQ_SET_INTERFACE; + req.wValue = alt; + req.wIndex = iface; + req.wLength = 0; + + set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); + udc->driver->setup(&udc->gadget, &req); +} + +/* + * irq_handle_data - Handle data transfer + * @irq: irq IRQ number + * @udc: dev pxa_udc device structure + * + * Called from irq handler, transferts data to or from endpoint to queue + */ +static void irq_handle_data(int irq, struct pxa_udc *udc) +{ + int i; + struct pxa_ep *ep; + u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK; + u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK; + + if (udcisr0 & UDCISR_INT_MASK) { + udc->pxa_ep[0].stats.irqs++; + udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK)); + handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR), + !!(udcisr0 & UDCICR_PKTCOMPL)); + } + + udcisr0 >>= 2; + for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) { + if (!(udcisr0 & UDCISR_INT_MASK)) + continue; + + udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK)); + ep = &udc->pxa_ep[i]; + ep->stats.irqs++; + handle_ep(ep); + } + + for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) { + udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK)); + if (!(udcisr1 & UDCISR_INT_MASK)) + continue; + + ep = &udc->pxa_ep[i]; + ep->stats.irqs++; + handle_ep(ep); + } + +} + +/** + * irq_udc_suspend - Handle IRQ "UDC Suspend" + * @udc: udc device + */ +static void irq_udc_suspend(struct pxa_udc *udc) +{ + udc_writel(udc, UDCISR1, UDCISR1_IRSU); + udc->stats.irqs_suspend++; + + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) + udc->driver->suspend(&udc->gadget); + ep0_idle(udc); +} + +/** + * irq_udc_resume - Handle IRQ "UDC Resume" + * @udc: udc device + */ +static void irq_udc_resume(struct pxa_udc *udc) +{ + udc_writel(udc, UDCISR1, UDCISR1_IRRU); + udc->stats.irqs_resume++; + + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) + udc->driver->resume(&udc->gadget); +} + +/** + * irq_udc_reconfig - Handle IRQ "UDC Change Configuration" + * @udc: udc device + */ +static void irq_udc_reconfig(struct pxa_udc *udc) +{ + unsigned config, interface, alternate, config_change; + u32 udccr = udc_readl(udc, UDCCR); + + udc_writel(udc, UDCISR1, UDCISR1_IRCC); + udc->stats.irqs_reconfig++; + + config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S; + config_change = (config != udc->config); + pxa27x_change_configuration(udc, config); + + interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S; + alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S; + pxa27x_change_interface(udc, interface, alternate); + + if (config_change) + update_pxa_ep_matches(udc); + udc_set_mask_UDCCR(udc, UDCCR_SMAC); +} + +/** + * irq_udc_reset - Handle IRQ "UDC Reset" + * @udc: udc device + */ +static void irq_udc_reset(struct pxa_udc *udc) +{ + u32 udccr = udc_readl(udc, UDCCR); + struct pxa_ep *ep = &udc->pxa_ep[0]; + + dev_info(udc->dev, "USB reset\n"); + udc_writel(udc, UDCISR1, UDCISR1_IRRS); + udc->stats.irqs_reset++; + + if ((udccr & UDCCR_UDA) == 0) { + dev_dbg(udc->dev, "USB reset start\n"); + stop_activity(udc, udc->driver); + } + udc->gadget.speed = USB_SPEED_FULL; + memset(&udc->stats, 0, sizeof udc->stats); + + nuke(ep, -EPROTO); + udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC); + ep0_idle(udc); +} + +/** + * pxa_udc_irq - Main irq handler + * @irq: irq number + * @_dev: udc device + * + * Handles all udc interrupts + */ +static irqreturn_t pxa_udc_irq(int irq, void *_dev) +{ + struct pxa_udc *udc = _dev; + u32 udcisr0 = udc_readl(udc, UDCISR0); + u32 udcisr1 = udc_readl(udc, UDCISR1); + u32 udccr = udc_readl(udc, UDCCR); + u32 udcisr1_spec; + + dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, " + "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr); + + udcisr1_spec = udcisr1 & 0xf8000000; + if (unlikely(udcisr1_spec & UDCISR1_IRSU)) + irq_udc_suspend(udc); + if (unlikely(udcisr1_spec & UDCISR1_IRRU)) + irq_udc_resume(udc); + if (unlikely(udcisr1_spec & UDCISR1_IRCC)) + irq_udc_reconfig(udc); + if (unlikely(udcisr1_spec & UDCISR1_IRRS)) + irq_udc_reset(udc); + + if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK)) + irq_handle_data(irq, udc); + + return IRQ_HANDLED; +} + +static struct pxa_udc memory = { + .gadget = { + .ops = &pxa_udc_ops, + .ep0 = &memory.udc_usb_ep[0].usb_ep, + .name = driver_name, + .dev = { + .bus_id = "gadget", + }, + }, + + .udc_usb_ep = { + USB_EP_CTRL, + USB_EP_OUT_BULK(1), + USB_EP_IN_BULK(2), + USB_EP_IN_ISO(3), + USB_EP_OUT_ISO(4), + USB_EP_IN_INT(5), + }, + + .pxa_ep = { + PXA_EP_CTRL, + /* Endpoints for gadget zero */ + PXA_EP_OUT_BULK(1, 1, 3, 0, 0), + PXA_EP_IN_BULK(2, 2, 3, 0, 0), + /* Endpoints for ether gadget, file storage gadget */ + PXA_EP_OUT_BULK(3, 1, 1, 0, 0), + PXA_EP_IN_BULK(4, 2, 1, 0, 0), + PXA_EP_IN_ISO(5, 3, 1, 0, 0), + PXA_EP_OUT_ISO(6, 4, 1, 0, 0), + PXA_EP_IN_INT(7, 5, 1, 0, 0), + /* Endpoints for RNDIS, serial */ + PXA_EP_OUT_BULK(8, 1, 2, 0, 0), + PXA_EP_IN_BULK(9, 2, 2, 0, 0), + PXA_EP_IN_INT(10, 5, 2, 0, 0), + /* + * All the following endpoints are only for completion. They + * won't never work, as multiple interfaces are really broken on + * the pxa. + */ + PXA_EP_OUT_BULK(11, 1, 2, 1, 0), + PXA_EP_IN_BULK(12, 2, 2, 1, 0), + /* Endpoint for CDC Ether */ + PXA_EP_OUT_BULK(13, 1, 1, 1, 1), + PXA_EP_IN_BULK(14, 2, 1, 1, 1), + } +}; + +/** + * pxa_udc_probe - probes the udc device + * @_dev: platform device + * + * Perform basic init : allocates udc clock, creates sysfs files, requests + * irq. + */ +static int __init pxa_udc_probe(struct platform_device *pdev) +{ + struct resource *regs; + struct pxa_udc *udc = &memory; + int retval; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + udc->irq = platform_get_irq(pdev, 0); + if (udc->irq < 0) + return udc->irq; + + udc->dev = &pdev->dev; + udc->mach = pdev->dev.platform_data; + + udc->clk = clk_get(&pdev->dev, "UDCCLK"); + if (IS_ERR(udc->clk)) { + retval = PTR_ERR(udc->clk); + goto err_clk; + } + + retval = -ENOMEM; + udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!udc->regs) { + dev_err(&pdev->dev, "Unable to map UDC I/O memory\n"); + goto err_map; + } + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = NULL; + + the_controller = udc; + platform_set_drvdata(pdev, udc); + udc_init_data(udc); + pxa_eps_setup(udc); + + /* irq setup after old hardware state is cleaned up */ + retval = request_irq(udc->irq, pxa_udc_irq, + IRQF_SHARED, driver_name, udc); + if (retval != 0) { + dev_err(udc->dev, "%s: can't get irq %i, err %d\n", + driver_name, IRQ_USB, retval); + goto err_irq; + } + + pxa_init_debugfs(udc); + return 0; +err_irq: + iounmap(udc->regs); +err_map: + clk_put(udc->clk); + udc->clk = NULL; +err_clk: + return retval; +} + +/** + * pxa_udc_remove - removes the udc device driver + * @_dev: platform device + */ +static int __exit pxa_udc_remove(struct platform_device *_dev) +{ + struct pxa_udc *udc = platform_get_drvdata(_dev); + + usb_gadget_unregister_driver(udc->driver); + free_irq(udc->irq, udc); + pxa_cleanup_debugfs(udc); + + platform_set_drvdata(_dev, NULL); + the_controller = NULL; + clk_put(udc->clk); + + return 0; +} + +static void pxa_udc_shutdown(struct platform_device *_dev) +{ + struct pxa_udc *udc = platform_get_drvdata(_dev); + + udc_disable(udc); +} + +#ifdef CONFIG_PM +/** + * pxa_udc_suspend - Suspend udc device + * @_dev: platform device + * @state: suspend state + * + * Suspends udc : saves configuration registers (UDCCR*), then disables the udc + * device. + */ +static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) +{ + int i; + struct pxa_udc *udc = platform_get_drvdata(_dev); + struct pxa_ep *ep; + + ep = &udc->pxa_ep[0]; + udc->udccsr0 = udc_ep_readl(ep, UDCCSR); + for (i = 1; i < NR_PXA_ENDPOINTS; i++) { + ep = &udc->pxa_ep[i]; + ep->udccsr_value = udc_ep_readl(ep, UDCCSR); + ep->udccr_value = udc_ep_readl(ep, UDCCR); + ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n", + ep->udccsr_value, ep->udccr_value); + } + + udc_disable(udc); + + return 0; +} + +/** + * pxa_udc_resume - Resume udc device + * @_dev: platform device + * + * Resumes udc : restores configuration registers (UDCCR*), then enables the udc + * device. + */ +static int pxa_udc_resume(struct platform_device *_dev) +{ + int i; + struct pxa_udc *udc = platform_get_drvdata(_dev); + struct pxa_ep *ep; + + ep = &udc->pxa_ep[0]; + udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME)); + for (i = 1; i < NR_PXA_ENDPOINTS; i++) { + ep = &udc->pxa_ep[i]; + udc_ep_writel(ep, UDCCSR, ep->udccsr_value); + udc_ep_writel(ep, UDCCR, ep->udccr_value); + ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n", + ep->udccsr_value, ep->udccr_value); + } + + udc_enable(udc); + /* + * We do not handle OTG yet. + * + * OTGPH bit is set when sleep mode is entered. + * it indicates that OTG pad is retaining its state. + * Upon exit from sleep mode and before clearing OTGPH, + * Software must configure the USB OTG pad, UDC, and UHC + * to the state they were in before entering sleep mode. + * + * Should be : PSSR |= PSSR_OTGPH; + */ + + return 0; +} +#endif + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:pxa2xx-udc"); + +static struct platform_driver udc_driver = { + .driver = { + .name = "pxa2xx-udc", + .owner = THIS_MODULE, + }, + .remove = __exit_p(pxa_udc_remove), + .shutdown = pxa_udc_shutdown, +#ifdef CONFIG_PM + .suspend = pxa_udc_suspend, + .resume = pxa_udc_resume +#endif +}; + +static int __init udc_init(void) +{ + printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); + return platform_driver_probe(&udc_driver, pxa_udc_probe); +} +module_init(udc_init); + + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h new file mode 100644 index 000000000000..1d1b7936ee11 --- /dev/null +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -0,0 +1,487 @@ +/* + * linux/drivers/usb/gadget/pxa27x_udc.h + * Intel PXA27x on-chip full speed USB device controller + * + * Inspired by original driver by Frank Becker, David Brownell, and others. + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_USB_GADGET_PXA27X_H +#define __LINUX_USB_GADGET_PXA27X_H + +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/io.h> + +/* + * Register definitions + */ +/* Offsets */ +#define UDCCR 0x0000 /* UDC Control Register */ +#define UDCICR0 0x0004 /* UDC Interrupt Control Register0 */ +#define UDCICR1 0x0008 /* UDC Interrupt Control Register1 */ +#define UDCISR0 0x000C /* UDC Interrupt Status Register 0 */ +#define UDCISR1 0x0010 /* UDC Interrupt Status Register 1 */ +#define UDCFNR 0x0014 /* UDC Frame Number Register */ +#define UDCOTGICR 0x0018 /* UDC On-The-Go interrupt control */ +#define UP2OCR 0x0020 /* USB Port 2 Output Control register */ +#define UP3OCR 0x0024 /* USB Port 3 Output Control register */ +#define UDCCSRn(x) (0x0100 + ((x)<<2)) /* UDC Control/Status register */ +#define UDCBCRn(x) (0x0200 + ((x)<<2)) /* UDC Byte Count Register */ +#define UDCDRn(x) (0x0300 + ((x)<<2)) /* UDC Data Register */ +#define UDCCRn(x) (0x0400 + ((x)<<2)) /* UDC Control Register */ + +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation + Protocol Port Support */ +#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol + Support */ +#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol + Enable */ +#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ +#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ +#define UDCCR_ACN_S 11 +#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ +#define UDCCR_AIN_S 8 +#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface + Setting Number */ +#define UDCCR_AAISN_S 5 +#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active + Configuration */ +#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration + Error */ +#define UDCCR_UDR (1 << 2) /* UDC Resume */ +#define UDCCR_UDA (1 << 1) /* UDC Active */ +#define UDCCR_UDE (1 << 0) /* UDC Enable */ + +#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ +#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ +#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ +#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ +#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ +#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ +#define UDCICR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL) + +#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */ +#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */ +#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */ +#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */ +#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */ +#define UDCISR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL) + +#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ +#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt + Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt + Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge + Interrupt Enable */ +#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge + Interrupt Enable */ +#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge + Interrupt Enable */ +#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising + Edge Interrupt Enable */ +#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling + Edge Interrupt Enable */ +#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge + Interrupt Enable */ +#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge + Interrupt Enable */ + +/* Host Port 2 field bits */ +#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */ +#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */ + /* Transceiver enablers */ +#define UP2OCR_DPPDE (1 << 2) /* D+ Pull Down Enable */ +#define UP2OCR_DMPDE (1 << 3) /* D- Pull Down Enable */ +#define UP2OCR_DPPUE (1 << 4) /* D+ Pull Up Enable */ +#define UP2OCR_DMPUE (1 << 5) /* D- Pull Up Enable */ +#define UP2OCR_DPPUBE (1 << 6) /* D+ Pull Up Bypass Enable */ +#define UP2OCR_DMPUBE (1 << 7) /* D- Pull Up Bypass Enable */ +#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */ +#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */ +#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */ +#define UP2OCR_HXS (1 << 16) /* Transceiver Output Select */ +#define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */ +#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ + +#define UDCCSR0_SA (1 << 7) /* Setup Active */ +#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ +#define UDCCSR0_FST (1 << 5) /* Force Stall */ +#define UDCCSR0_SST (1 << 4) /* Sent Stall */ +#define UDCCSR0_DME (1 << 3) /* DMA Enable */ +#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ +#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ +#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ + +#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ +#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ +#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ +#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ +#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ +#define UDCCSR_FST (1 << 5) /* Force STALL */ +#define UDCCSR_SST (1 << 4) /* Sent STALL */ +#define UDCCSR_DME (1 << 3) /* DMA Enable */ +#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ +#define UDCCSR_PC (1 << 1) /* Packet Complete */ +#define UDCCSR_FS (1 << 0) /* FIFO needs service */ + +#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ +#define UDCCONR_CN_S 25 +#define UDCCONR_IN (0x07 << 22) /* Interface Number */ +#define UDCCONR_IN_S 22 +#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ +#define UDCCONR_AISN_S 19 +#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ +#define UDCCONR_EN_S 15 +#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ +#define UDCCONR_ET_S 13 +#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ +#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ +#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ +#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ +#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ +#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ +#define UDCCONR_MPS_S 2 +#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ +#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ + +#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE) +#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST) +#define UDC_FNR_MASK (0x7ff) +#define UDC_BCR_MASK (0x3ff) + +/* + * UDCCR = UDC Endpoint Configuration Registers + * UDCCSR = UDC Control/Status Register for this EP + * UDCBCR = UDC Byte Count Remaining (contents of OUT fifo) + * UDCDR = UDC Endpoint Data Register (the fifo) + */ +#define ofs_UDCCR(ep) (UDCCRn(ep->idx)) +#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx)) +#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx)) +#define ofs_UDCDR(ep) (UDCDRn(ep->idx)) + +/* Register access macros */ +#define udc_ep_readl(ep, reg) \ + __raw_readl((ep)->dev->regs + ofs_##reg(ep)) +#define udc_ep_writel(ep, reg, value) \ + __raw_writel((value), ep->dev->regs + ofs_##reg(ep)) +#define udc_ep_readb(ep, reg) \ + __raw_readb((ep)->dev->regs + ofs_##reg(ep)) +#define udc_ep_writeb(ep, reg, value) \ + __raw_writeb((value), ep->dev->regs + ofs_##reg(ep)) +#define udc_readl(dev, reg) \ + __raw_readl((dev)->regs + (reg)) +#define udc_writel(udc, reg, value) \ + __raw_writel((value), (udc)->regs + (reg)) + +#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME) +#define UDCCISR0_EP_MASK ~0 +#define UDCCISR1_EP_MASK 0xffff +#define UDCCSR0_CTRL_REQ_MASK (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE) + +#define EPIDX(ep) (ep->idx) +#define EPADDR(ep) (ep->addr) +#define EPXFERTYPE(ep) (ep->type) +#define EPNAME(ep) (ep->name) +#define is_ep0(ep) (!ep->idx) +#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC) + +/* + * Endpoint definitions + * + * Once enabled, pxa endpoint configuration is freezed, and cannot change + * unless a reset happens or the udc is disabled. + * Therefore, we must define all pxa potential endpoint definitions needed for + * all gadget and set them up before the udc is enabled. + * + * As the architecture chosen is fully static, meaning the pxa endpoint + * configurations are set up once and for all, we must provide a way to match + * one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget + * layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt) + * criteria, while the pxa architecture requires that. + * + * The solution is to define several pxa endpoints matching one usb_ep. Ex: + * - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when + * the udc talks on (config=3, interface=0, alt=0) + * - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when + * the udc talks on (config=3, interface=0, alt=1) + * - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when + * the udc talks on (config=2, interface=0, alt=0) + * + * We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...) + */ + +/* + * Endpoint definition helpers + */ +#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \ +{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \ + .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \ + .bmAttributes = type, \ + .wMaxPacketSize = maxpkt, }, \ + .dev = &memory \ +} +#define USB_EP_BULK(addr, bname, dir) \ + USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE) +#define USB_EP_ISO(addr, bname, dir) \ + USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE) +#define USB_EP_INT(addr, bname, dir) \ + USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE) +#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1) +#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0) +#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1) +#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0) +#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1) +#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE) + +#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \ +{ \ + .dev = &memory, \ + .name = "ep" #_idx, \ + .idx = _idx, .enabled = 0, \ + .dir_in = dir, .addr = _addr, \ + .config = _config, .interface = iface, .alternate = altset, \ + .type = _type, .fifo_size = maxpkt, \ +} +#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \ + PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \ + config, iface, alt) +#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \ + PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \ + config, iface, alt) +#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \ + PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \ + config, iface, alt) +#define PXA_EP_IN_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 1, c, f, a) +#define PXA_EP_OUT_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 0, c, f, a) +#define PXA_EP_IN_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 1, c, f, a) +#define PXA_EP_OUT_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 0, c, f, a) +#define PXA_EP_IN_INT(i, adr, c, f, a) PXA_EP_INT(i, adr, 1, c, f, a) +#define PXA_EP_CTRL PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0) + +struct pxa27x_udc; + +struct stats { + unsigned long in_ops; + unsigned long out_ops; + unsigned long in_bytes; + unsigned long out_bytes; + unsigned long irqs; +}; + +/** + * struct udc_usb_ep - container of each usb_ep structure + * @usb_ep: usb endpoint + * @desc: usb descriptor, especially type and address + * @dev: udc managing this endpoint + * @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call) + */ +struct udc_usb_ep { + struct usb_ep usb_ep; + struct usb_endpoint_descriptor desc; + struct pxa_udc *dev; + struct pxa_ep *pxa_ep; +}; + +/** + * struct pxa_ep - pxa endpoint + * @dev: udc device + * @queue: requests queue + * @lock: lock to pxa_ep data (queues and stats) + * @enabled: true when endpoint enabled (not stopped by gadget layer) + * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX) + * @name: endpoint name (for trace/debug purpose) + * @dir_in: 1 if IN endpoint, 0 if OUT endpoint + * @addr: usb endpoint number + * @config: configuration in which this endpoint is active + * @interface: interface in which this endpoint is active + * @alternate: altsetting in which this endpoitn is active + * @fifo_size: max packet size in the endpoint fifo + * @type: endpoint type (bulk, iso, int, ...) + * @udccsr_value: save register of UDCCSR0 for suspend/resume + * @udccr_value: save register of UDCCR for suspend/resume + * @stats: endpoint statistics + * + * The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned + * (cares about config/interface/altsetting, thus placing needless limits on + * device capability) and full of implementation bugs forcing it to be set up + * for use more or less like a pxa255. + * + * As we define the pxa_ep statically, we must guess all needed pxa_ep for all + * gadget which may work with this udc driver. + */ +struct pxa_ep { + struct pxa_udc *dev; + + struct list_head queue; + spinlock_t lock; /* Protects this structure */ + /* (queues, stats) */ + unsigned enabled:1; + + unsigned idx:5; + char *name; + + /* + * Specific pxa endpoint data, needed for hardware initialization + */ + unsigned dir_in:1; + unsigned addr:3; + unsigned config:2; + unsigned interface:3; + unsigned alternate:3; + unsigned fifo_size; + unsigned type; + +#ifdef CONFIG_PM + u32 udccsr_value; + u32 udccr_value; +#endif + struct stats stats; +}; + +/** + * struct pxa27x_request - container of each usb_request structure + * @req: usb request + * @udc_usb_ep: usb endpoint the request was submitted on + * @in_use: sanity check if request already queued on an pxa_ep + * @queue: linked list of requests, linked on pxa_ep->queue + */ +struct pxa27x_request { + struct usb_request req; + struct udc_usb_ep *udc_usb_ep; + unsigned in_use:1; + struct list_head queue; +}; + +enum ep0_state { + WAIT_FOR_SETUP, + SETUP_STAGE, + IN_DATA_STAGE, + OUT_DATA_STAGE, + IN_STATUS_STAGE, + OUT_STATUS_STAGE, + STALL, + WAIT_ACK_SET_CONF_INTERF +}; + +static char *ep0_state_name[] = { + "WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE", + "IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL", + "WAIT_ACK_SET_CONF_INTERF" +}; +#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state] + +#define EP0_FIFO_SIZE 16U +#define BULK_FIFO_SIZE 64U +#define ISO_FIFO_SIZE 256U +#define INT_FIFO_SIZE 16U + +struct udc_stats { + unsigned long irqs_reset; + unsigned long irqs_suspend; + unsigned long irqs_resume; + unsigned long irqs_reconfig; +}; + +#define NR_USB_ENDPOINTS (1 + 5) /* ep0 + ep1in-bulk + .. + ep3in-iso */ +#define NR_PXA_ENDPOINTS (1 + 14) /* ep0 + epA + epB + .. + epX */ + +/** + * struct pxa_udc - udc structure + * @regs: mapped IO space + * @irq: udc irq + * @clk: udc clock + * @usb_gadget: udc gadget structure + * @driver: bound gadget (zero, g_ether, g_file_storage, ...) + * @dev: device + * @mach: machine info, used to activate specific GPIO + * @ep0state: control endpoint state machine state + * @stats: statistics on udc usage + * @udc_usb_ep: array of usb endpoints offered by the gadget + * @pxa_ep: array of pxa available endpoints + * @config: UDC active configuration + * @last_interface: UDC interface of the last SET_INTERFACE host request + * @last_alternate: UDC altsetting of the last SET_INTERFACE host request + * @udccsr0: save of udccsr0 in case of suspend + * @debugfs_root: root entry of debug filesystem + * @debugfs_state: debugfs entry for "udcstate" + * @debugfs_queues: debugfs entry for "queues" + * @debugfs_eps: debugfs entry for "epstate" + */ +struct pxa_udc { + void __iomem *regs; + int irq; + struct clk *clk; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct device *dev; + struct pxa2xx_udc_mach_info *mach; + + enum ep0_state ep0state; + struct udc_stats stats; + + struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS]; + struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS]; + + unsigned config:2; + unsigned last_interface:3; + unsigned last_alternate:3; + +#ifdef CONFIG_PM + unsigned udccsr0; +#endif +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *debugfs_state; + struct dentry *debugfs_queues; + struct dentry *debugfs_eps; +#endif +}; + +static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct pxa_udc, gadget); +} + +/* + * Debugging/message support + */ +#define ep_dbg(ep, fmt, arg...) \ + dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) +#define ep_vdbg(ep, fmt, arg...) \ + dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) +#define ep_err(ep, fmt, arg...) \ + dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) +#define ep_info(ep, fmt, arg...) \ + dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) +#define ep_warn(ep, fmt, arg...) \ + dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg) + +#endif /* __LINUX_USB_GADGET_PXA27X_H */ diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index bd58dd504f6f..d0677f5d3cd5 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -183,14 +183,10 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, DBG("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); } } @@ -666,7 +662,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_PNP_QUERY_POWER: DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__, - le32_to_cpu(get_unaligned((__le32 *)buf)) - 1); + get_unaligned_le32(buf) - 1); /* only suspend is a real power state, and * it can't be entered by OID_PNP_SET_POWER... */ @@ -705,14 +701,10 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, DBG("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); } } @@ -726,8 +718,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - *params->filter = (u16) le32_to_cpu(get_unaligned( - (__le32 *)buf)); + *params->filter = (u16)get_unaligned_le32(buf); DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", __func__, *params->filter); @@ -777,7 +768,7 @@ update_linkstate: * resuming, Windows forces a reset, and then SET_POWER D0. * FIXME ... then things go batty; Windows wedges itself. */ - i = le32_to_cpu(get_unaligned((__le32 *)buf)); + i = get_unaligned_le32(buf); DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1); switch (i) { case NdisDeviceStateD0: @@ -1064,8 +1055,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOMEM; tmp = (__le32 *) buf; - MsgType = le32_to_cpu(get_unaligned(tmp++)); - MsgLength = le32_to_cpu(get_unaligned(tmp++)); + MsgType = get_unaligned_le32(tmp++); + MsgLength = get_unaligned_le32(tmp++); if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; @@ -1296,10 +1287,9 @@ int rndis_rm_hdr(struct sk_buff *skb) tmp++; /* DataOffset, DataLength */ - if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++)) - + 8 /* offset of DataOffset */)) + if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) return -EOVERFLOW; - skb_trim(skb, le32_to_cpu(get_unaligned(tmp++))); + skb_trim(skb, get_unaligned_le32(tmp++)); return 0; } diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 433b3f44f42e..54cdd6f94034 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -135,7 +135,10 @@ struct gs_port { int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ struct gs_buf *port_write_buf; - struct usb_cdc_line_coding port_line_coding; + struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ + u16 port_handshake_bits; +#define RS232_RTS (1 << 1) +#define RS232_DTE (1 << 0) }; /* the device structure holds info for the USB device */ @@ -170,7 +173,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); @@ -199,6 +202,8 @@ static int gs_setup_standard(struct usb_gadget *gadget, static int gs_setup_class(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl); static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req); +static void gs_setup_complete_set_line_coding(struct usb_ep *ep, + struct usb_request *req); static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); @@ -406,7 +411,7 @@ static struct usb_cdc_acm_descriptor gs_acm_descriptor = { .bLength = sizeof(gs_acm_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bmCapabilities = (1 << 1), }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -883,14 +888,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 +916,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; } /* @@ -1500,6 +1507,8 @@ static int gs_setup(struct usb_gadget *gadget, u16 wValue = le16_to_cpu(ctrl->wValue); u16 wLength = le16_to_cpu(ctrl->wLength); + req->complete = gs_setup_complete; + switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: ret = gs_setup_standard(gadget,ctrl); @@ -1677,18 +1686,14 @@ static int gs_setup_class(struct usb_gadget *gadget, switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: - /* FIXME Submit req to read the data; have its completion - * handler copy that data to port->port_line_coding (iff - * it's valid) and maybe pass it on. Until then, fail. - */ - pr_warning("gs_setup: set_line_coding " - "unuspported\n"); + if (wLength != sizeof(struct usb_cdc_line_coding)) + break; + ret = wLength; + req->complete = gs_setup_complete_set_line_coding; break; case USB_CDC_REQ_GET_LINE_CODING: - port = dev->dev_port[0]; /* ACM only has one port */ - ret = min(wLength, - (u16)sizeof(struct usb_cdc_line_coding)); + ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding)); if (port) { spin_lock(&port->port_lock); memcpy(req->buf, &port->port_line_coding, ret); @@ -1697,15 +1702,27 @@ static int gs_setup_class(struct usb_gadget *gadget, break; case USB_CDC_REQ_SET_CONTROL_LINE_STATE: - /* FIXME Submit req to read the data; have its completion - * handler use that to set the state (iff it's valid) and - * maybe pass it on. Until then, fail. - */ - pr_warning("gs_setup: set_control_line_state " - "unuspported\n"); + if (wLength != 0) + break; + ret = 0; + if (port) { + /* REVISIT: we currently just remember this data. + * If we change that, update whatever hardware needs + * updating. + */ + spin_lock(&port->port_lock); + port->port_handshake_bits = wValue; + spin_unlock(&port->port_lock); + } break; default: + /* NOTE: strictly speaking, we should accept AT-commands + * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE. + * But our call management descriptor says we don't handle + * call management, so we should be able to get by without + * handling those "required" commands (except by stalling). + */ pr_err("gs_setup: unknown class request, " "type=%02x, request=%02x, value=%04x, " "index=%04x, length=%d\n", @@ -1717,6 +1734,42 @@ static int gs_setup_class(struct usb_gadget *gadget, return ret; } +static void gs_setup_complete_set_line_coding(struct usb_ep *ep, + struct usb_request *req) +{ + struct gs_dev *dev = ep->driver_data; + struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ + + switch (req->status) { + case 0: + /* normal completion */ + if (req->actual != sizeof(port->port_line_coding)) + usb_ep_set_halt(ep); + else if (port) { + struct usb_cdc_line_coding *value = req->buf; + + /* REVISIT: we currently just remember this data. + * If we change that, (a) validate it first, then + * (b) update whatever hardware needs updating. + */ + spin_lock(&port->port_lock); + port->port_line_coding = *value; + spin_unlock(&port->port_lock); + } + break; + + case -ESHUTDOWN: + /* disconnect */ + gs_free_req(ep, req); + break; + + default: + /* unexpected */ + break; + } + return; +} + /* * gs_setup_complete */ @@ -1904,6 +1957,11 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } } + /* REVISIT the ACM mode should be able to actually *issue* some + * notifications, for at least serial state change events if + * not also for network connection; say so in bmCapabilities. + */ + pr_info("gs_set_config: %s configured, %s speed %s config\n", GS_LONG_NAME, gadget->speed == USB_SPEED_HIGH ? "high" : "full", diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 878e428a0ec1..4154be375c7a 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -74,7 +74,7 @@ static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) goto fail; } else uchar = c; - put_unaligned (cpu_to_le16 (uchar), cp++); + put_unaligned_le16(uchar, cp++); count++; len--; } diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index d3d4f4048e6c..fce4924dbbe8 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -23,9 +23,7 @@ /* * Gadget Zero only needs two bulk endpoints, and is an example of how you * can write a hardware-agnostic gadget driver running inside a USB device. - * - * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't - * affect most of the driver. + * Some hardware details are visible, but don't affect most of the driver. * * Use it with the Linux host/master side "usbtest" driver to get a basic * functional test of your device-side usb stack, or with "usb-skeleton". @@ -37,6 +35,7 @@ * buflen=N default N=4096, buffer size used * qlen=N default N=32, how many buffers in the loopback queue * loopdefault default false, list loopback config first + * autoresume=N default N=0, seconds before triggering remote wakeup * * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this @@ -62,13 +61,13 @@ /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "Lughnasadh, 2007" +#define DRIVER_VERSION "Earth Day 2008" -static const char shortname [] = "zero"; -static const char longname [] = "Gadget Zero"; +static const char shortname[] = "zero"; +static const char longname[] = "Gadget Zero"; -static const char source_sink [] = "source and sink data"; -static const char loopback [] = "loop input to output"; +static const char source_sink[] = "source and sink data"; +static const char loopback[] = "loop input to output"; /*-------------------------------------------------------------------------*/ @@ -120,16 +119,16 @@ static unsigned buflen = 4096; static unsigned qlen = 32; static unsigned pattern = 0; -module_param (buflen, uint, S_IRUGO); -module_param (qlen, uint, S_IRUGO); -module_param (pattern, uint, S_IRUGO|S_IWUSR); +module_param(buflen, uint, S_IRUGO); +module_param(qlen, uint, S_IRUGO); +module_param(pattern, uint, S_IRUGO|S_IWUSR); /* * if it's nonzero, autoresume says how many seconds to wait * before trying to wake up the host after suspend. */ static unsigned autoresume = 0; -module_param (autoresume, uint, 0); +module_param(autoresume, uint, 0); /* * Normally the "loopback" configuration is second (index 1) so @@ -138,8 +137,7 @@ module_param (autoresume, uint, 0); * Or controllers (like superh) that only support one config. */ static int loopdefault = 0; - -module_param (loopdefault, bool, S_IRUGO|S_IWUSR); +module_param(loopdefault, bool, S_IRUGO|S_IWUSR); /*-------------------------------------------------------------------------*/ @@ -176,24 +174,22 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR); #define CONFIG_SOURCE_SINK 3 #define CONFIG_LOOPBACK 2 -static struct usb_device_descriptor -device_desc = { +static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), + .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .iSerialNumber = STRING_SERIAL, .bNumConfigurations = 2, }; -static struct usb_config_descriptor -source_sink_config = { +static struct usb_config_descriptor source_sink_config = { .bLength = sizeof source_sink_config, .bDescriptorType = USB_DT_CONFIG, @@ -205,8 +201,7 @@ source_sink_config = { .bMaxPower = 1, /* self-powered */ }; -static struct usb_config_descriptor -loopback_config = { +static struct usb_config_descriptor loopback_config = { .bLength = sizeof loopback_config, .bDescriptorType = USB_DT_CONFIG, @@ -218,8 +213,7 @@ loopback_config = { .bMaxPower = 1, /* self-powered */ }; -static struct usb_otg_descriptor -otg_descriptor = { +static struct usb_otg_descriptor otg_descriptor = { .bLength = sizeof otg_descriptor, .bDescriptorType = USB_DT_OTG, @@ -228,8 +222,7 @@ otg_descriptor = { /* one interface in each configuration */ -static const struct usb_interface_descriptor -source_sink_intf = { +static const struct usb_interface_descriptor source_sink_intf = { .bLength = sizeof source_sink_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -238,8 +231,7 @@ source_sink_intf = { .iInterface = STRING_SOURCE_SINK, }; -static const struct usb_interface_descriptor -loopback_intf = { +static const struct usb_interface_descriptor loopback_intf = { .bLength = sizeof loopback_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -250,8 +242,7 @@ loopback_intf = { /* two full speed bulk endpoints; their use is config-dependent */ -static struct usb_endpoint_descriptor -fs_source_desc = { +static struct usb_endpoint_descriptor fs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -259,8 +250,7 @@ fs_source_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor -fs_sink_desc = { +static struct usb_endpoint_descriptor fs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -268,7 +258,7 @@ fs_sink_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static const struct usb_descriptor_header *fs_source_sink_function [] = { +static const struct usb_descriptor_header *fs_source_sink_function[] = { (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &fs_sink_desc, @@ -276,7 +266,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = { NULL, }; -static const struct usb_descriptor_header *fs_loopback_function [] = { +static const struct usb_descriptor_header *fs_loopback_function[] = { (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &fs_sink_desc, @@ -293,36 +283,33 @@ static const struct usb_descriptor_header *fs_loopback_function [] = { * for the config descriptor. */ -static struct usb_endpoint_descriptor -hs_source_desc = { +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (512), + .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_endpoint_descriptor -hs_sink_desc = { +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (512), + .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_qualifier_descriptor -dev_qualifier = { +static struct usb_qualifier_descriptor dev_qualifier = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, .bNumConfigurations = 2, }; -static const struct usb_descriptor_header *hs_source_sink_function [] = { +static const struct usb_descriptor_header *hs_source_sink_function[] = { (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &hs_source_desc, @@ -330,7 +317,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = { NULL, }; -static const struct usb_descriptor_header *hs_loopback_function [] = { +static const struct usb_descriptor_header *hs_loopback_function[] = { (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &hs_source_desc, @@ -355,7 +342,7 @@ static char serial[] = "0123456789.0123456789.0123456789"; /* static strings, in UTF-8 */ -static struct usb_string strings [] = { +static struct usb_string strings[] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { STRING_SERIAL, serial, }, @@ -364,7 +351,7 @@ static struct usb_string strings [] = { { } /* end of list */ }; -static struct usb_gadget_strings stringtab = { +static struct usb_gadget_strings stringtab = { .language = 0x0409, /* en-us */ .strings = strings, }; @@ -387,8 +374,7 @@ static struct usb_gadget_strings stringtab = { * high bandwidth modes at high speed. (Maybe work like Intel's test * device?) */ -static int -config_buf (struct usb_gadget *gadget, +static int config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { int is_source_sink; @@ -419,7 +405,7 @@ config_buf (struct usb_gadget *gadget, if (!gadget_is_otg(gadget)) function++; - len = usb_gadget_config_buf (is_source_sink + len = usb_gadget_config_buf(is_source_sink ? &source_sink_config : &loopback_config, buf, USB_BUFSIZ, function); @@ -431,27 +417,26 @@ config_buf (struct usb_gadget *gadget, /*-------------------------------------------------------------------------*/ -static struct usb_request * -alloc_ep_req (struct usb_ep *ep, unsigned length) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; - req = usb_ep_alloc_request (ep, GFP_ATOMIC); + req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req) { req->length = length; req->buf = kmalloc(length, GFP_ATOMIC); if (!req->buf) { - usb_ep_free_request (ep, req); + usb_ep_free_request(ep, req); req = NULL; } } return req; } -static void free_ep_req (struct usb_ep *ep, struct usb_request *req) +static void free_ep_req(struct usb_ep *ep, struct usb_request *req) { kfree(req->buf); - usb_ep_free_request (ep, req); + usb_ep_free_request(ep, req); } /*-------------------------------------------------------------------------*/ @@ -472,7 +457,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /* optionally require specific source/sink data patterns */ static int -check_read_data ( +check_read_data( struct zero_dev *dev, struct usb_ep *ep, struct usb_request *req @@ -498,8 +483,8 @@ check_read_data ( continue; break; } - ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf); - usb_ep_set_halt (ep); + ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf); + usb_ep_set_halt(ep); return -EINVAL; } return 0; @@ -512,7 +497,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) switch (pattern) { case 0: - memset (req->buf, 0, req->length); + memset(req->buf, 0, req->length); break; case 1: for (i = 0; i < req->length; i++) @@ -525,7 +510,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) * irq delay between end of one request and start of the next. * that prevents using hardware dma queues. */ -static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) +static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) { struct zero_dev *dev = ep->driver_data; int status = req->status; @@ -534,8 +519,8 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) case 0: /* normal completion? */ if (ep == dev->out_ep) { - check_read_data (dev, ep, req); - memset (req->buf, 0x55, req->length); + check_read_data(dev, ep, req); + memset(req->buf, 0x55, req->length); } else reinit_write_data(ep, req); break; @@ -544,11 +529,11 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ - VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, + VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); if (ep == dev->out_ep) - check_read_data (dev, ep, req); - free_ep_req (ep, req); + check_read_data(dev, ep, req); + free_ep_req(ep, req); return; case -EOVERFLOW: /* buffer overrun on read means that @@ -557,18 +542,18 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) */ default: #if 1 - DBG (dev, "%s complete --> %d, %d/%d\n", ep->name, + DBG(dev, "%s complete --> %d, %d/%d\n", ep->name, status, req->actual, req->length); #endif case -EREMOTEIO: /* short read */ break; } - status = usb_ep_queue (ep, req, GFP_ATOMIC); + status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { - ERROR (dev, "kill %s: resubmit %d bytes --> %d\n", + ERROR(dev, "kill %s: resubmit %d bytes --> %d\n", ep->name, req->length, status); - usb_ep_set_halt (ep); + usb_ep_set_halt(ep); /* FIXME recover later ... somehow */ } } @@ -578,24 +563,24 @@ static struct usb_request *source_sink_start_ep(struct usb_ep *ep) struct usb_request *req; int status; - req = alloc_ep_req (ep, buflen); + req = alloc_ep_req(ep, buflen); if (!req) return NULL; - memset (req->buf, 0, req->length); + memset(req->buf, 0, req->length); req->complete = source_sink_complete; - if (strcmp (ep->name, EP_IN_NAME) == 0) + if (strcmp(ep->name, EP_IN_NAME) == 0) reinit_write_data(ep, req); else - memset (req->buf, 0x55, req->length); + memset(req->buf, 0x55, req->length); status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { struct zero_dev *dev = ep->driver_data; - ERROR (dev, "start %s --> %d\n", ep->name, status); - free_ep_req (ep, req); + ERROR(dev, "start %s --> %d\n", ep->name, status); + free_ep_req(ep, req); req = NULL; } @@ -608,34 +593,34 @@ static int set_source_sink_config(struct zero_dev *dev) struct usb_ep *ep; struct usb_gadget *gadget = dev->gadget; - gadget_for_each_ep (ep, gadget) { + gadget_for_each_ep(ep, gadget) { const struct usb_endpoint_descriptor *d; /* one endpoint writes (sources) zeroes in (to the host) */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); - result = usb_ep_enable (ep, d); + if (strcmp(ep->name, EP_IN_NAME) == 0) { + d = ep_desc(gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable(ep, d); if (result == 0) { ep->driver_data = dev; if (source_sink_start_ep(ep) != NULL) { dev->in_ep = ep; continue; } - usb_ep_disable (ep); + usb_ep_disable(ep); result = -EIO; } /* one endpoint reads (sinks) anything out (from the host) */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); - result = usb_ep_enable (ep, d); + } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { + d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable(ep, d); if (result == 0) { ep->driver_data = dev; if (source_sink_start_ep(ep) != NULL) { dev->out_ep = ep; continue; } - usb_ep_disable (ep); + usb_ep_disable(ep); result = -EIO; } @@ -644,11 +629,11 @@ static int set_source_sink_config(struct zero_dev *dev) continue; /* stop on error */ - ERROR (dev, "can't start %s, result %d\n", ep->name, result); + ERROR(dev, "can't start %s, result %d\n", ep->name, result); break; } if (result == 0) - DBG (dev, "buflen %d\n", buflen); + DBG(dev, "buflen %d\n", buflen); /* caller is responsible for cleanup on error */ return result; @@ -656,7 +641,7 @@ static int set_source_sink_config(struct zero_dev *dev) /*-------------------------------------------------------------------------*/ -static void loopback_complete (struct usb_ep *ep, struct usb_request *req) +static void loopback_complete(struct usb_ep *ep, struct usb_request *req) { struct zero_dev *dev = ep->driver_data; int status = req->status; @@ -668,19 +653,19 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); req->length = req->actual; - status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); + status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC); if (status == 0) return; /* "should never get here" */ - ERROR (dev, "can't loop %s to %s: %d\n", + ERROR(dev, "can't loop %s to %s: %d\n", ep->name, dev->in_ep->name, status); } /* queue the buffer for some later OUT packet */ req->length = buflen; - status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC); + status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); if (status == 0) return; @@ -688,7 +673,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ default: - ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name, + ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name, status, req->actual, req->length); /* FALLTHROUGH */ @@ -700,7 +685,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ - free_ep_req (ep, req); + free_ep_req(ep, req); return; } } @@ -711,13 +696,13 @@ static int set_loopback_config(struct zero_dev *dev) struct usb_ep *ep; struct usb_gadget *gadget = dev->gadget; - gadget_for_each_ep (ep, gadget) { + gadget_for_each_ep(ep, gadget) { const struct usb_endpoint_descriptor *d; /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); - result = usb_ep_enable (ep, d); + if (strcmp(ep->name, EP_IN_NAME) == 0) { + d = ep_desc(gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable(ep, d); if (result == 0) { ep->driver_data = dev; dev->in_ep = ep; @@ -725,9 +710,9 @@ static int set_loopback_config(struct zero_dev *dev) } /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); - result = usb_ep_enable (ep, d); + } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { + d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable(ep, d); if (result == 0) { ep->driver_data = dev; dev->out_ep = ep; @@ -739,7 +724,7 @@ static int set_loopback_config(struct zero_dev *dev) continue; /* stop on error */ - ERROR (dev, "can't enable %s, result %d\n", ep->name, result); + ERROR(dev, "can't enable %s, result %d\n", ep->name, result); break; } @@ -753,19 +738,19 @@ static int set_loopback_config(struct zero_dev *dev) ep = dev->out_ep; for (i = 0; i < qlen && result == 0; i++) { - req = alloc_ep_req (ep, buflen); + req = alloc_ep_req(ep, buflen); if (req) { req->complete = loopback_complete; - result = usb_ep_queue (ep, req, GFP_ATOMIC); + result = usb_ep_queue(ep, req, GFP_ATOMIC); if (result) - DBG (dev, "%s queue req --> %d\n", + DBG(dev, "%s queue req --> %d\n", ep->name, result); } else result = -ENOMEM; } } if (result == 0) - DBG (dev, "qlen %d, buflen %d\n", qlen, buflen); + DBG(dev, "qlen %d, buflen %d\n", qlen, buflen); /* caller is responsible for cleanup on error */ return result; @@ -773,26 +758,26 @@ static int set_loopback_config(struct zero_dev *dev) /*-------------------------------------------------------------------------*/ -static void zero_reset_config (struct zero_dev *dev) +static void zero_reset_config(struct zero_dev *dev) { if (dev->config == 0) return; - DBG (dev, "reset config\n"); + DBG(dev, "reset config\n"); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. */ if (dev->in_ep) { - usb_ep_disable (dev->in_ep); + usb_ep_disable(dev->in_ep); dev->in_ep = NULL; } if (dev->out_ep) { - usb_ep_disable (dev->out_ep); + usb_ep_disable(dev->out_ep); dev->out_ep = NULL; } dev->config = 0; - del_timer (&dev->resume); + del_timer(&dev->resume); } /* change our operational config. this code must agree with the code @@ -813,12 +798,12 @@ static int zero_set_config(struct zero_dev *dev, unsigned number) if (number == dev->config) return 0; - if (gadget_is_sa1100 (gadget) && dev->config) { + if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ ERROR(dev, "can't change configurations\n"); return -ESPIPE; } - zero_reset_config (dev); + zero_reset_config(dev); switch (number) { case CONFIG_SOURCE_SINK: @@ -837,7 +822,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number) if (!result && (!dev->in_ep || !dev->out_ep)) result = -ENODEV; if (result) - zero_reset_config (dev); + zero_reset_config(dev); else { char *speed; @@ -849,7 +834,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number) } dev->config = number; - INFO (dev, "%s speed config #%d: %s\n", speed, number, + INFO(dev, "%s speed config #%d: %s\n", speed, number, (number == CONFIG_SOURCE_SINK) ? source_sink : loopback); } @@ -858,10 +843,10 @@ static int zero_set_config(struct zero_dev *dev, unsigned number) /*-------------------------------------------------------------------------*/ -static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req) +static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) - DBG ((struct zero_dev *) ep->driver_data, + DBG((struct zero_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); } @@ -874,9 +859,9 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req) * the work is in config-specific setup. */ static int -zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { - struct zero_dev *dev = get_gadget_data (gadget); + struct zero_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); @@ -895,14 +880,14 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) switch (w_value >> 8) { case USB_DT_DEVICE: - value = min (w_length, (u16) sizeof device_desc); - memcpy (req->buf, &device_desc, value); + value = min(w_length, (u16) sizeof device_desc); + memcpy(req->buf, &device_desc, value); break; case USB_DT_DEVICE_QUALIFIER: if (!gadget_is_dualspeed(gadget)) break; - value = min (w_length, (u16) sizeof dev_qualifier); - memcpy (req->buf, &dev_qualifier, value); + value = min(w_length, (u16) sizeof dev_qualifier); + memcpy(req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: @@ -910,11 +895,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; // FALLTHROUGH case USB_DT_CONFIG: - value = config_buf (gadget, req->buf, + value = config_buf(gadget, req->buf, w_value >> 8, w_value & 0xff); if (value >= 0) - value = min (w_length, (u16) value); + value = min(w_length, (u16) value); break; case USB_DT_STRING: @@ -923,10 +908,10 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * add string tables for other languages, using * any UTF-8 characters */ - value = usb_gadget_get_string (&stringtab, + value = usb_gadget_get_string(&stringtab, w_value & 0xff, req->buf); if (value >= 0) - value = min (w_length, (u16) value); + value = min(w_length, (u16) value); break; } break; @@ -936,20 +921,20 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (ctrl->bRequestType != 0) goto unknown; if (gadget->a_hnp_support) - DBG (dev, "HNP available\n"); + DBG(dev, "HNP available\n"); else if (gadget->a_alt_hnp_support) - DBG (dev, "HNP needs a different root port\n"); + DBG(dev, "HNP needs a different root port\n"); else - VDBG (dev, "HNP inactive\n"); - spin_lock (&dev->lock); + VDBG(dev, "HNP inactive\n"); + spin_lock(&dev->lock); value = zero_set_config(dev, w_value); - spin_unlock (&dev->lock); + spin_unlock(&dev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; *(u8 *)req->buf = dev->config; - value = min (w_length, (u16) 1); + value = min(w_length, (u16) 1); break; /* until we add altsetting support, or other interfaces, @@ -959,7 +944,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; - spin_lock (&dev->lock); + spin_lock(&dev->lock); if (dev->config && w_index == 0 && w_value == 0) { u8 config = dev->config; @@ -970,11 +955,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * if we had more than one interface we couldn't * use this "reset the config" shortcut. */ - zero_reset_config (dev); + zero_reset_config(dev); zero_set_config(dev, config); value = 0; } - spin_unlock (&dev->lock); + spin_unlock(&dev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) @@ -986,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; } *(u8 *)req->buf = 0; - value = min (w_length, (u16) 1); + value = min(w_length, (u16) 1); break; /* @@ -1018,7 +1003,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) default: unknown: - VDBG (dev, + VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); @@ -1028,11 +1013,11 @@ unknown: if (value >= 0) { req->length = value; req->zero = value < w_length; - value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { - DBG (dev, "ep_queue --> %d\n", value); + DBG(dev, "ep_queue --> %d\n", value); req->status = 0; - zero_setup_complete (gadget->ep0, req); + zero_setup_complete(gadget->ep0, req); } } @@ -1040,28 +1025,26 @@ unknown: return value; } -static void -zero_disconnect (struct usb_gadget *gadget) +static void zero_disconnect(struct usb_gadget *gadget) { - struct zero_dev *dev = get_gadget_data (gadget); + struct zero_dev *dev = get_gadget_data(gadget); unsigned long flags; - spin_lock_irqsave (&dev->lock, flags); - zero_reset_config (dev); + spin_lock_irqsave(&dev->lock, flags); + zero_reset_config(dev); /* a more significant application might have some non-usb * activities to quiesce here, saving resources like power * or pushing the notification up a network stack. */ - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->lock, flags); /* next we may get setup() calls to enumerate new connections; * or an unbind() during shutdown (including removing module). */ } -static void -zero_autoresume (unsigned long _dev) +static void zero_autoresume(unsigned long _dev) { struct zero_dev *dev = (struct zero_dev *) _dev; int status; @@ -1070,32 +1053,30 @@ zero_autoresume (unsigned long _dev) * more significant than just a timer firing... */ if (dev->gadget->speed != USB_SPEED_UNKNOWN) { - status = usb_gadget_wakeup (dev->gadget); - DBG (dev, "wakeup --> %d\n", status); + status = usb_gadget_wakeup(dev->gadget); + DBG(dev, "wakeup --> %d\n", status); } } /*-------------------------------------------------------------------------*/ -static void /* __init_or_exit */ -zero_unbind (struct usb_gadget *gadget) +static void zero_unbind(struct usb_gadget *gadget) { - struct zero_dev *dev = get_gadget_data (gadget); + struct zero_dev *dev = get_gadget_data(gadget); - DBG (dev, "unbind\n"); + DBG(dev, "unbind\n"); /* we've already been disconnected ... no i/o is active */ if (dev->req) { dev->req->length = USB_BUFSIZ; - free_ep_req (gadget->ep0, dev->req); + free_ep_req(gadget->ep0, dev->req); } - del_timer_sync (&dev->resume); - kfree (dev); - set_gadget_data (gadget, NULL); + del_timer_sync(&dev->resume); + kfree(dev); + set_gadget_data(gadget, NULL); } -static int __init -zero_bind (struct usb_gadget *gadget) +static int __init zero_bind(struct usb_gadget *gadget) { struct zero_dev *dev; struct usb_ep *ep; @@ -1111,8 +1092,8 @@ zero_bind (struct usb_gadget *gadget) * autoconfigure on any sane usb controller driver, * but there may also be important quirks to address. */ - usb_ep_autoconfig_reset (gadget); - ep = usb_ep_autoconfig (gadget, &fs_source_desc); + usb_ep_autoconfig_reset(gadget); + ep = usb_ep_autoconfig(gadget, &fs_source_desc); if (!ep) { autoconf_fail: pr_err("%s: can't autoconfigure on %s\n", @@ -1122,15 +1103,15 @@ autoconf_fail: EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - ep = usb_ep_autoconfig (gadget, &fs_sink_desc); + ep = usb_ep_autoconfig(gadget, &fs_sink_desc); if (!ep) goto autoconf_fail; EP_OUT_NAME = ep->name; ep->driver_data = ep; /* claim */ - gcnum = usb_gadget_controller_number (gadget); + gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum); + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. @@ -1141,7 +1122,7 @@ autoconf_fail: */ pr_warning("%s: controller '%s' not recognized\n", shortname, gadget->name); - device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999); + device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } @@ -1149,12 +1130,16 @@ autoconf_fail: dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - spin_lock_init (&dev->lock); + spin_lock_init(&dev->lock); dev->gadget = gadget; - set_gadget_data (gadget, dev); + set_gadget_data(gadget, dev); + + init_timer(&dev->resume); + dev->resume.function = zero_autoresume; + dev->resume.data = (unsigned long) dev; /* preallocate control response and buffer */ - dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); + dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!dev->req) goto enomem; dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); @@ -1182,11 +1167,8 @@ autoconf_fail: loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - usb_gadget_set_selfpowered (gadget); + usb_gadget_set_selfpowered(gadget); - init_timer (&dev->resume); - dev->resume.function = zero_autoresume; - dev->resume.data = (unsigned long) dev; if (autoresume) { source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1194,45 +1176,43 @@ autoconf_fail: gadget->ep0->driver_data = dev; - INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); - INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, + INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname); + INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, EP_OUT_NAME, EP_IN_NAME); - snprintf (manufacturer, sizeof manufacturer, "%s %s with %s", + snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", init_utsname()->sysname, init_utsname()->release, gadget->name); return 0; enomem: - zero_unbind (gadget); + zero_unbind(gadget); return -ENOMEM; } /*-------------------------------------------------------------------------*/ -static void -zero_suspend (struct usb_gadget *gadget) +static void zero_suspend(struct usb_gadget *gadget) { - struct zero_dev *dev = get_gadget_data (gadget); + struct zero_dev *dev = get_gadget_data(gadget); if (gadget->speed == USB_SPEED_UNKNOWN) return; if (autoresume) { - mod_timer (&dev->resume, jiffies + (HZ * autoresume)); - DBG (dev, "suspend, wakeup in %d seconds\n", autoresume); + mod_timer(&dev->resume, jiffies + (HZ * autoresume)); + DBG(dev, "suspend, wakeup in %d seconds\n", autoresume); } else - DBG (dev, "suspend\n"); + DBG(dev, "suspend\n"); } -static void -zero_resume (struct usb_gadget *gadget) +static void zero_resume(struct usb_gadget *gadget) { - struct zero_dev *dev = get_gadget_data (gadget); + struct zero_dev *dev = get_gadget_data(gadget); - DBG (dev, "resume\n"); - del_timer (&dev->resume); + DBG(dev, "resume\n"); + del_timer(&dev->resume); } @@ -1264,15 +1244,15 @@ MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); -static int __init init (void) +static int __init init(void) { - return usb_gadget_register_driver (&zero_driver); + return usb_gadget_register_driver(&zero_driver); } -module_init (init); +module_init(init); -static void __exit cleanup (void) +static void __exit cleanup(void) { - usb_gadget_unregister_driver (&zero_driver); + usb_gadget_unregister_driver(&zero_driver); } -module_exit (cleanup); +module_exit(cleanup); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0b87480dd713..33b467a8352d 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -4,6 +4,19 @@ comment "USB Host Controller Drivers" depends on USB +config USB_C67X00_HCD + tristate "Cypress C67x00 HCD support" + depends on USB + help + The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role + host/peripheral/OTG USB controllers. + + Enable this option to support this chip in host controller mode. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called c67x00. + config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" depends on USB && USB_ARCH_HAS_EHCI @@ -95,6 +108,32 @@ config USB_ISP116X_HCD To compile this driver as a module, choose M here: the module will be called isp116x-hcd. +config USB_ISP1760_HCD + tristate "ISP 1760 HCD support" + depends on USB && EXPERIMENTAL + ---help--- + The ISP1760 chip is a USB 2.0 host controller. + + This driver does not support isochronous transfers or OTG. + + To compile this driver as a module, choose M here: the + module will be called isp1760-hcd. + +config USB_ISP1760_PCI + bool "Support for the PCI bus" + depends on USB_ISP1760_HCD && PCI + ---help--- + Enables support for the device present on the PCI bus. + This should only be required if you happen to have the eval kit from + NXP and you are going to test it. + +config USB_ISP1760_OF + bool "Support for the OF platform bus" + depends on USB_ISP1760_HCD && OF + ---help--- + Enables support for the device present on the PowerPC + OpenFirmware platform bus. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB && USB_ARCH_HAS_OHCI diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index bb8e9d44f371..f1edda2dcfde 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif +isp1760-objs := isp1760-hcd.o isp1760-if.o + obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o @@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o - +obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 4af90df8e7de..0f82fdcaef09 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -398,7 +398,7 @@ static void qh_lines ( unsigned size = *sizep; char *next = *nextp; char mark; - u32 list_end = EHCI_LIST_END(ehci); + __le32 list_end = EHCI_LIST_END(ehci); if (qh->hw_qtd_next == list_end) /* NEC does this */ mark = '@'; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index efffef64f59d..382587c4457c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -530,7 +530,7 @@ ehci_hub_descriptor ( if (HCS_INDICATOR (ehci->hcs_params)) temp |= 0x0080; /* per-port indicators (LEDs) */ #endif - desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp); + desc->wHubCharacteristics = cpu_to_le16(temp); } /*-------------------------------------------------------------------------*/ @@ -770,7 +770,7 @@ static int ehci_hub_control ( if (status & ~0xffff) /* only if wPortChange is interesting */ #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); - put_unaligned(cpu_to_le32 (status), (__le32 *) buf); + put_unaligned_le32(status, buf); break; case SetHubFeature: switch (wValue) { diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5ae689139dd0..b85b54160cda 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -285,7 +285,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) int stopped; unsigned count = 0; u8 state; - u32 halt = HALT_BIT(ehci); + __le32 halt = HALT_BIT(ehci); if (unlikely (list_empty (&qh->qtd_list))) return count; @@ -883,7 +883,7 @@ static struct ehci_qh *qh_append_tds ( ) { struct ehci_qh *qh = NULL; - u32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); + __hc32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); qh = (struct ehci_qh *) *ptr; if (unlikely (qh == NULL)) { diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c new file mode 100644 index 000000000000..4ba96c1e060c --- /dev/null +++ b/drivers/usb/host/isp1760-hcd.c @@ -0,0 +1,2231 @@ +/* + * Driver for the NXP ISP1760 chip + * + * However, the code might contain some bugs. What doesn't work for sure is: + * - ISO + * - OTG + e The interrupt line is configured as active low, level. + * + * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/usb.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <asm/unaligned.h> + +#include "../core/hcd.h" +#include "isp1760-hcd.h" + +static struct kmem_cache *qtd_cachep; +static struct kmem_cache *qh_cachep; + +struct isp1760_hcd { + u32 hcs_params; + spinlock_t lock; + struct inter_packet_info atl_ints[32]; + struct inter_packet_info int_ints[32]; + struct memory_chunk memory_pool[BLOCKS]; + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 + unsigned periodic_size; + unsigned i_thresh; + unsigned long reset_done; + unsigned long next_statechange; +}; + +static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) +{ + return (struct isp1760_hcd *) (hcd->hcd_priv); +} +static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv) +{ + return container_of((void *) priv, struct usb_hcd, hcd_priv); +} + +/* Section 2.2 Host Controller Capability Registers */ +#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ +#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ +#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ +#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ +#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ +#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ + +/* Section 2.3 Host Controller Operational Registers */ +#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ +#define STS_PCD (1<<2) /* port change detect */ +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + +#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC) + +struct isp1760_qtd { + struct isp1760_qtd *hw_next; + u8 packet_type; + u8 toggle; + + void *data_buffer; + /* the rest is HCD-private */ + struct list_head qtd_list; + struct urb *urb; + size_t length; + + /* isp special*/ + u32 status; +#define URB_COMPLETE_NOTIFY (1 << 0) +#define URB_ENQUEUED (1 << 1) +#define URB_TYPE_ATL (1 << 2) +#define URB_TYPE_INT (1 << 3) +}; + +struct isp1760_qh { + /* first part defined by EHCI spec */ + struct list_head qtd_list; + struct isp1760_hcd *priv; + + /* periodic schedule info */ + unsigned short period; /* polling interval */ + struct usb_device *dev; + + u32 toggle; + u32 ping; +}; + +#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED) + +static unsigned int isp1760_readl(__u32 __iomem *regs) +{ + return readl(regs); +} + +static void isp1760_writel(const unsigned int val, __u32 __iomem *regs) +{ + writel(val, regs); +} + +/* + * The next two copy via MMIO data to/from the device. memcpy_{to|from}io() + * doesn't quite work because some people have to enforce 32-bit access + */ +static void priv_read_copy(struct isp1760_hcd *priv, u32 *src, + __u32 __iomem *dst, u32 offset, u32 len) +{ + struct usb_hcd *hcd = priv_to_hcd(priv); + u32 val; + u8 *buff8; + + if (!src) { + printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len); + return; + } + isp1760_writel(offset, hcd->regs + HC_MEMORY_REG); + /* XXX + * 90nsec delay, the spec says something how this could be avoided. + */ + mdelay(1); + + while (len >= 4) { + *src = __raw_readl(dst); + len -= 4; + src++; + dst++; + } + + if (!len) + return; + + /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully + * allocated. + */ + val = isp1760_readl(dst); + + buff8 = (u8 *)src; + while (len) { + + *buff8 = val; + val >>= 8; + len--; + buff8++; + } +} + +static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src, + __u32 __iomem *dst, u32 len) +{ + while (len >= 4) { + __raw_writel(*src, dst); + len -= 4; + src++; + dst++; + } + + if (!len) + return; + /* in case we have 3, 2 or 1 by left. The buffer is allocated and the + * extra bytes should not be read by the HW + */ + + __raw_writel(*src, dst); +} + +/* memory management of the 60kb on the chip from 0x1000 to 0xffff */ +static void init_memory(struct isp1760_hcd *priv) +{ + int i; + u32 payload; + + payload = 0x1000; + for (i = 0; i < BLOCK_1_NUM; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_1_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + + for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_2_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + + for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_3_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE); +} + +static u32 alloc_mem(struct isp1760_hcd *priv, u32 size) +{ + int i; + + if (!size) + return ISP1760_NULL_POINTER; + + for (i = 0; i < BLOCKS; i++) { + if (priv->memory_pool[i].size >= size && + priv->memory_pool[i].free) { + + priv->memory_pool[i].free = 0; + return priv->memory_pool[i].start; + } + } + + printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n", + size); + printk(KERN_ERR "Current memory map:\n"); + for (i = 0; i < BLOCKS; i++) { + printk(KERN_ERR "Pool %2d size %4d status: %d\n", + i, priv->memory_pool[i].size, + priv->memory_pool[i].free); + } + /* XXX maybe -ENOMEM could be possible */ + BUG(); + return 0; +} + +static void free_mem(struct isp1760_hcd *priv, u32 mem) +{ + int i; + + if (mem == ISP1760_NULL_POINTER) + return; + + for (i = 0; i < BLOCKS; i++) { + if (priv->memory_pool[i].start == mem) { + + BUG_ON(priv->memory_pool[i].free); + + priv->memory_pool[i].free = 1; + return ; + } + } + + printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n", + mem); + BUG(); +} + +static void isp1760_init_regs(struct usb_hcd *hcd) +{ + isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_ISO_PTD_SKIPMAP_REG); + + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_ATL_PTD_DONEMAP_REG); + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_INT_PTD_DONEMAP_REG); + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_ISO_PTD_DONEMAP_REG); +} + +static int handshake(struct isp1760_hcd *priv, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = isp1760_readl(ptr); + if (result == ~0) + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* reset a non-running (STS_HALT == 1) controller */ +static int ehci_reset(struct isp1760_hcd *priv) +{ + int retval; + struct usb_hcd *hcd = priv_to_hcd(priv); + u32 command = isp1760_readl(hcd->regs + HC_USBCMD); + + command |= CMD_RESET; + isp1760_writel(command, hcd->regs + HC_USBCMD); + hcd->state = HC_STATE_HALT; + priv->next_statechange = jiffies; + retval = handshake(priv, hcd->regs + HC_USBCMD, + CMD_RESET, 0, 250 * 1000); + return retval; +} + +static void qh_destroy(struct isp1760_qh *qh) +{ + BUG_ON(!list_empty(&qh->qtd_list)); + kmem_cache_free(qh_cachep, qh); +} + +static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv, + gfp_t flags) +{ + struct isp1760_qh *qh; + + qh = kmem_cache_zalloc(qh_cachep, flags); + if (!qh) + return qh; + + INIT_LIST_HEAD(&qh->qtd_list); + qh->priv = priv; + return qh; +} + +/* magic numbers that can affect system performance */ +#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ +#define EHCI_TUNE_RL_TT 0 +#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define EHCI_TUNE_MULT_TT 1 +#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ + +/* one-time init, only for memory state */ +static int priv_init(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 hcc_params; + + spin_lock_init(&priv->lock); + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + priv->periodic_size = DEFAULT_I_TDPS; + + /* controllers may cache some of the periodic schedule ... */ + hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS); + /* full frame cache */ + if (HCC_ISOC_CACHE(hcc_params)) + priv->i_thresh = 8; + else /* N microframes cached */ + priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); + + return 0; +} + +static int isp1760_hc_setup(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int result; + u32 scratch; + + isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG); + scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG); + if (scratch != 0xdeadbabe) { + printk(KERN_ERR "ISP1760: Scratch test failed.\n"); + return -ENODEV; + } + + /* pre reset */ + isp1760_init_regs(hcd); + + /* reset */ + isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG); + mdelay(100); + + isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG); + mdelay(100); + + result = ehci_reset(priv); + if (result) + return result; + + /* Step 11 passed */ + + isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG); + isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE); + + /* ATL reset */ + scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); + isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL); + mdelay(10); + isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL); + + isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL); + mdelay(10); + + priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS); + + return priv_init(hcd); +} + +static void isp1760_init_maps(struct usb_hcd *hcd) +{ + /*set last maps, for iso its only 1, else 32 tds bitmap*/ + isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG); + isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG); + isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG); +} + +static void isp1760_enable_interrupts(struct usb_hcd *hcd) +{ + isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG); + isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG); + isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG); + isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG); + /* step 23 passed */ +} + +static int isp1760_run(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int retval; + u32 temp; + u32 command; + u32 chipid; + + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + + hcd->state = HC_STATE_RUNNING; + isp1760_enable_interrupts(hcd); + temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); + temp |= FINAL_HW_CONFIG; + isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL); + + command = isp1760_readl(hcd->regs + HC_USBCMD); + command &= ~(CMD_LRESET|CMD_RESET); + command |= CMD_RUN; + isp1760_writel(command, hcd->regs + HC_USBCMD); + + retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN, + 250 * 1000); + if (retval) + return retval; + + /* + * XXX + * Spec says to write FLAG_CF as last config action, priv code grabs + * the semaphore while doing so. + */ + down_write(&ehci_cf_port_reset_rwsem); + isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG); + + retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF, + 250 * 1000); + up_write(&ehci_cf_port_reset_rwsem); + if (retval) + return retval; + + chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG); + isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff, + chipid >> 16); + + /* PTD Register Init Part 2, Step 28 */ + /* enable INTs */ + isp1760_init_maps(hcd); + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + return 0; +} + +static u32 base_to_chip(u32 base) +{ + return ((base - 0x400) >> 3); +} + +static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + u32 dw0; + u32 dw1; + u32 dw2; + u32 dw3; + u32 maxpacket; + u32 multi; + u32 pid_code; + u32 rl = RL_COUNTER; + u32 nak = NAK_COUNTER; + + /* according to 3.6.2, max packet len can not be > 0x400 */ + maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + multi = 1 + ((maxpacket >> 11) & 0x3); + maxpacket &= 0x7ff; + + /* DW0 */ + dw0 = PTD_VALID; + dw0 |= PTD_LENGTH(qtd->length); + dw0 |= PTD_MAXPACKET(maxpacket); + dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe)); + dw1 = usb_pipeendpoint(urb->pipe) >> 1; + + /* DW1 */ + dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe)); + + pid_code = qtd->packet_type; + dw1 |= PTD_PID_TOKEN(pid_code); + + if (usb_pipebulk(urb->pipe)) + dw1 |= PTD_TRANS_BULK; + else if (usb_pipeint(urb->pipe)) + dw1 |= PTD_TRANS_INT; + + if (urb->dev->speed != USB_SPEED_HIGH) { + /* split transaction */ + + dw1 |= PTD_TRANS_SPLIT; + if (urb->dev->speed == USB_SPEED_LOW) + dw1 |= PTD_SE_USB_LOSPEED; + + dw1 |= PTD_PORT_NUM(urb->dev->ttport); + dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum); + + /* SE bit for Split INT transfers */ + if (usb_pipeint(urb->pipe) && + (urb->dev->speed == USB_SPEED_LOW)) + dw1 |= 2 << 16; + + dw3 = 0; + rl = 0; + nak = 0; + } else { + dw0 |= PTD_MULTI(multi); + if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) + dw3 = qh->ping; + else + dw3 = 0; + } + /* DW2 */ + dw2 = 0; + dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload)); + dw2 |= PTD_RL_CNT(rl); + dw3 |= PTD_NAC_CNT(nak); + + /* DW3 */ + if (usb_pipecontrol(urb->pipe)) + dw3 |= PTD_DATA_TOGGLE(qtd->toggle); + else + dw3 |= qh->toggle; + + + dw3 |= PTD_ACTIVE; + /* Cerr */ + dw3 |= PTD_CERR(ERR_COUNTER); + + memset(ptd, 0, sizeof(*ptd)); + + ptd->dw0 = cpu_to_le32(dw0); + ptd->dw1 = cpu_to_le32(dw1); + ptd->dw2 = cpu_to_le32(dw2); + ptd->dw3 = cpu_to_le32(dw3); +} + +static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + u32 maxpacket; + u32 multi; + u32 numberofusofs; + u32 i; + u32 usofmask, usof; + u32 period; + + maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + multi = 1 + ((maxpacket >> 11) & 0x3); + maxpacket &= 0x7ff; + /* length of the data per uframe */ + maxpacket = multi * maxpacket; + + numberofusofs = urb->transfer_buffer_length / maxpacket; + if (urb->transfer_buffer_length % maxpacket) + numberofusofs += 1; + + usofmask = 1; + usof = 0; + for (i = 0; i < numberofusofs; i++) { + usof |= usofmask; + usofmask <<= 1; + } + + if (urb->dev->speed != USB_SPEED_HIGH) { + /* split */ + ptd->dw5 = __constant_cpu_to_le32(0x1c); + + if (qh->period >= 32) + period = qh->period / 2; + else + period = qh->period; + + } else { + + if (qh->period >= 8) + period = qh->period/8; + else + period = qh->period; + + if (period >= 32) + period = 16; + + if (qh->period >= 8) { + /* millisecond period */ + period = (period << 3); + } else { + /* usof based tranmsfers */ + /* minimum 4 usofs */ + usof = 0x11; + } + } + + ptd->dw2 |= cpu_to_le32(period); + ptd->dw4 = cpu_to_le32(usof); +} + +static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + transform_into_atl(priv, qh, qtd, urb, payload, ptd); + transform_add_int(priv, qh, qtd, urb, payload, ptd); +} + +static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len, + u32 token) +{ + int count; + + qtd->data_buffer = databuffer; + qtd->packet_type = GET_QTD_TOKEN_TYPE(token); + qtd->toggle = GET_DATA_TOGGLE(token); + + if (len > HC_ATL_PL_SIZE) + count = HC_ATL_PL_SIZE; + else + count = len; + + qtd->length = count; + return count; +} + +static int check_error(struct ptd *ptd) +{ + int error = 0; + u32 dw3; + + dw3 = le32_to_cpu(ptd->dw3); + if (dw3 & DW3_HALT_BIT) + error = -EPIPE; + + if (dw3 & DW3_ERROR_BIT) { + printk(KERN_ERR "error bit is set in DW3\n"); + error = -EPIPE; + } + + if (dw3 & DW3_QTD_ACTIVE) { + printk(KERN_ERR "transfer active bit is set DW3\n"); + printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf, + (le32_to_cpu(ptd->dw2) >> 25) & 0xf); + } + + return error; +} + +static void check_int_err_status(u32 dw4) +{ + u32 i; + + dw4 >>= 8; + + for (i = 0; i < 8; i++) { + switch (dw4 & 0x7) { + case INT_UNDERRUN: + printk(KERN_ERR "ERROR: under run , %d\n", i); + break; + + case INT_EXACT: + printk(KERN_ERR "ERROR: transaction error, %d\n", i); + break; + + case INT_BABBLE: + printk(KERN_ERR "ERROR: babble error, %d\n", i); + break; + } + dw4 >>= 3; + } +} + +static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv, + u32 payload) +{ + u32 token; + struct usb_hcd *hcd = priv_to_hcd(priv); + + token = qtd->packet_type; + + if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) { + switch (token) { + case IN_PID: + break; + case OUT_PID: + case SETUP_PID: + priv_write_copy(priv, qtd->data_buffer, + hcd->regs + payload, + qtd->length); + } + } +} + +static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload, + struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +{ + struct ptd ptd; + struct usb_hcd *hcd = priv_to_hcd(priv); + + transform_into_atl(priv, qh, qtd, urb, payload, &ptd); + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd)); + enqueue_one_qtd(qtd, priv, payload); + + priv->atl_ints[slot].urb = urb; + priv->atl_ints[slot].qh = qh; + priv->atl_ints[slot].qtd = qtd; + priv->atl_ints[slot].data_buffer = qtd->data_buffer; + priv->atl_ints[slot].payload = payload; + qtd->status |= URB_ENQUEUED | URB_TYPE_ATL; + qtd->status |= slot << 16; +} + +static void enqueue_one_int_qtd(u32 int_regs, u32 payload, + struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +{ + struct ptd ptd; + struct usb_hcd *hcd = priv_to_hcd(priv); + + transform_into_int(priv, qh, qtd, urb, payload, &ptd); + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd)); + enqueue_one_qtd(qtd, priv, payload); + + priv->int_ints[slot].urb = urb; + priv->int_ints[slot].qh = qh; + priv->int_ints[slot].qtd = qtd; + priv->int_ints[slot].data_buffer = qtd->data_buffer; + priv->int_ints[slot].payload = payload; + qtd->status |= URB_ENQUEUED | URB_TYPE_INT; + qtd->status |= slot << 16; +} + +void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 skip_map, or_map; + u32 queue_entry; + u32 slot; + u32 atl_regs, payload; + u32 buffstatus; + + skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + + BUG_ON(!skip_map); + slot = __ffs(skip_map); + queue_entry = 1 << slot; + + atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd); + + payload = alloc_mem(priv, qtd->length); + + enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd); + + or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + or_map |= queue_entry; + isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + + skip_map &= ~queue_entry; + isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + + buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); + buffstatus |= ATL_BUFFER; + isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); +} + +void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 skip_map, or_map; + u32 queue_entry; + u32 slot; + u32 int_regs, payload; + u32 buffstatus; + + skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); + + BUG_ON(!skip_map); + slot = __ffs(skip_map); + queue_entry = 1 << slot; + + int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd); + + payload = alloc_mem(priv, qtd->length); + + enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd); + + or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG); + or_map |= queue_entry; + isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + + skip_map &= ~queue_entry; + isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG); + + buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); + buffstatus |= INT_BUFFER; + isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); +} + +static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status) +__releases(priv->lock) +__acquires(priv->lock) +{ + if (!urb->unlinked) { + if (status == -EINPROGRESS) + status = 0; + } + + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); + spin_unlock(&priv->lock); + usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status); + spin_lock(&priv->lock); +} + +static void isp1760_qtd_free(struct isp1760_qtd *qtd) +{ + kmem_cache_free(qtd_cachep, qtd); +} + +static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd) +{ + struct isp1760_qtd *tmp_qtd; + + tmp_qtd = qtd->hw_next; + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + return tmp_qtd; +} + +/* + * Remove this QTD from the QH list and free its memory. If this QTD + * isn't the last one than remove also his successor(s). + * Returns the QTD which is part of an new URB and should be enqueued. + */ +static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd) +{ + struct isp1760_qtd *tmp_qtd; + int last_one; + + do { + tmp_qtd = qtd->hw_next; + last_one = qtd->status & URB_COMPLETE_NOTIFY; + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + qtd = tmp_qtd; + } while (!last_one && qtd); + + return qtd; +} + +static void do_atl_int(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 done_map, skip_map; + struct ptd ptd; + struct urb *urb = NULL; + u32 atl_regs_base; + u32 atl_regs; + u32 queue_entry; + u32 payload; + u32 length; + u32 or_map; + u32 status = -EINVAL; + int error; + struct isp1760_qtd *qtd; + struct isp1760_qh *qh; + u32 rl; + u32 nakcount; + + done_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_DONEMAP_REG); + skip_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + + or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + or_map &= ~done_map; + isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + + atl_regs_base = ATL_REGS_OFFSET; + while (done_map) { + u32 dw1; + u32 dw2; + u32 dw3; + + status = 0; + + queue_entry = __ffs(done_map); + done_map &= ~(1 << queue_entry); + skip_map |= 1 << queue_entry; + + atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd); + + urb = priv->atl_ints[queue_entry].urb; + qtd = priv->atl_ints[queue_entry].qtd; + qh = priv->atl_ints[queue_entry].qh; + payload = priv->atl_ints[queue_entry].payload; + + if (!qh) { + printk(KERN_ERR "qh is 0\n"); + continue; + } + priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs, + atl_regs, sizeof(ptd)); + + dw1 = le32_to_cpu(ptd.dw1); + dw2 = le32_to_cpu(ptd.dw2); + dw3 = le32_to_cpu(ptd.dw3); + rl = (dw2 >> 25) & 0x0f; + nakcount = (dw3 >> 19) & 0xf; + + /* Transfer Error, *but* active and no HALT -> reload */ + if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) && + !(dw3 & DW3_HALT_BIT)) { + + /* according to ppriv code, we have to + * reload this one if trasfered bytes != requested bytes + * else act like everything went smooth.. + * XXX This just doesn't feel right and hasn't + * triggered so far. + */ + + length = PTD_XFERRED_LENGTH(dw3); + printk(KERN_ERR "Should reload now.... transfered %d " + "of %zu\n", length, qtd->length); + BUG(); + } + + if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) { + u32 buffstatus; + + /* XXX + * NAKs are handled in HW by the chip. Usually if the + * device is not able to send data fast enough. + * This did not trigger for a long time now. + */ + printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: " + "%d of %d done: %08x cur: %08x\n", qtd, + urb, qh, PTD_XFERRED_LENGTH(dw3), + qtd->length, done_map, + (1 << queue_entry)); + + /* RL counter = ERR counter */ + dw3 &= ~(0xf << 19); + dw3 |= rl << 19; + dw3 &= ~(3 << (55 - 32)); + dw3 |= ERR_COUNTER << (55 - 32); + + /* + * It is not needed to write skip map back because it + * is unchanged. Just make sure that this entry is + * unskipped once it gets written to the HW. + */ + skip_map &= ~(1 << queue_entry); + or_map = isp1760_readl(usb_hcd->regs + + HC_ATL_IRQ_MASK_OR_REG); + or_map |= 1 << queue_entry; + isp1760_writel(or_map, usb_hcd->regs + + HC_ATL_IRQ_MASK_OR_REG); + + ptd.dw3 = cpu_to_le32(dw3); + priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + + atl_regs, sizeof(ptd)); + + ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID); + priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + + atl_regs, sizeof(ptd)); + + buffstatus = isp1760_readl(usb_hcd->regs + + HC_BUFFER_STATUS_REG); + buffstatus |= ATL_BUFFER; + isp1760_writel(buffstatus, usb_hcd->regs + + HC_BUFFER_STATUS_REG); + continue; + } + + error = check_error(&ptd); + if (error) { + status = error; + priv->atl_ints[queue_entry].qh->toggle = 0; + priv->atl_ints[queue_entry].qh->ping = 0; + urb->status = -EPIPE; + +#if 0 + printk(KERN_ERR "Error in %s().\n", __func__); + printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " + "dw3: %08x dw4: %08x dw5: %08x dw6: " + "%08x dw7: %08x\n", + ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, + ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); +#endif + } else { + if (usb_pipetype(urb->pipe) == PIPE_BULK) { + priv->atl_ints[queue_entry].qh->toggle = dw3 & + (1 << 25); + priv->atl_ints[queue_entry].qh->ping = dw3 & + (1 << 26); + } + } + + length = PTD_XFERRED_LENGTH(dw3); + if (length) { + switch (DW1_GET_PID(dw1)) { + case IN_PID: + priv_read_copy(priv, + priv->atl_ints[queue_entry].data_buffer, + usb_hcd->regs + payload, payload, + length); + + case OUT_PID: + + urb->actual_length += length; + + case SETUP_PID: + break; + } + } + + priv->atl_ints[queue_entry].data_buffer = NULL; + priv->atl_ints[queue_entry].urb = NULL; + priv->atl_ints[queue_entry].qtd = NULL; + priv->atl_ints[queue_entry].qh = NULL; + + free_mem(priv, payload); + + isp1760_writel(skip_map, usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + + if (urb->status == -EPIPE) { + /* HALT was received */ + + qtd = clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) { + /* short BULK received */ + + printk(KERN_ERR "short bulk, %d instead %d\n", length, + qtd->length); + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + urb->status = -EREMOTEIO; + printk(KERN_ERR "not okey\n"); + } + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_up_qtdlist(qtd); + + isp1760_urb_done(priv, urb, urb->status); + + } else if (qtd->status & URB_COMPLETE_NOTIFY) { + /* that was the last qtd of that URB */ + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_this_qtd(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else { + /* next QTD of this URB */ + + qtd = clean_this_qtd(qtd); + BUG_ON(!qtd); + } + + if (qtd) + enqueue_an_ATL_packet(usb_hcd, qh, qtd); + + skip_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + } +} + +static void do_intl_int(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 done_map, skip_map; + struct ptd ptd; + struct urb *urb = NULL; + u32 int_regs; + u32 int_regs_base; + u32 payload; + u32 length; + u32 or_map; + int error; + u32 queue_entry; + struct isp1760_qtd *qtd; + struct isp1760_qh *qh; + + done_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_DONEMAP_REG); + skip_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + + or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); + or_map &= ~done_map; + isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); + + int_regs_base = INT_REGS_OFFSET; + + while (done_map) { + u32 dw1; + u32 dw3; + + queue_entry = __ffs(done_map); + done_map &= ~(1 << queue_entry); + skip_map |= 1 << queue_entry; + + int_regs = int_regs_base + queue_entry * sizeof(struct ptd); + urb = priv->int_ints[queue_entry].urb; + qtd = priv->int_ints[queue_entry].qtd; + qh = priv->int_ints[queue_entry].qh; + payload = priv->int_ints[queue_entry].payload; + + if (!qh) { + printk(KERN_ERR "(INT) qh is 0\n"); + continue; + } + + priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs, + int_regs, sizeof(ptd)); + dw1 = le32_to_cpu(ptd.dw1); + dw3 = le32_to_cpu(ptd.dw3); + check_int_err_status(le32_to_cpu(ptd.dw4)); + + error = check_error(&ptd); + if (error) { +#if 0 + printk(KERN_ERR "Error in %s().\n", __func__); + printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " + "dw3: %08x dw4: %08x dw5: %08x dw6: " + "%08x dw7: %08x\n", + ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, + ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); +#endif + urb->status = -EPIPE; + priv->int_ints[queue_entry].qh->toggle = 0; + priv->int_ints[queue_entry].qh->ping = 0; + + } else { + priv->int_ints[queue_entry].qh->toggle = + dw3 & (1 << 25); + priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26); + } + + if (urb->dev->speed != USB_SPEED_HIGH) + length = PTD_XFERRED_LENGTH_LO(dw3); + else + length = PTD_XFERRED_LENGTH(dw3); + + if (length) { + switch (DW1_GET_PID(dw1)) { + case IN_PID: + priv_read_copy(priv, + priv->int_ints[queue_entry].data_buffer, + usb_hcd->regs + payload , payload, + length); + case OUT_PID: + + urb->actual_length += length; + + case SETUP_PID: + break; + } + } + + priv->int_ints[queue_entry].data_buffer = NULL; + priv->int_ints[queue_entry].urb = NULL; + priv->int_ints[queue_entry].qtd = NULL; + priv->int_ints[queue_entry].qh = NULL; + + isp1760_writel(skip_map, usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + free_mem(priv, payload); + + if (urb->status == -EPIPE) { + /* HALT received */ + + qtd = clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else if (qtd->status & URB_COMPLETE_NOTIFY) { + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_this_qtd(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else { + /* next QTD of this URB */ + + qtd = clean_this_qtd(qtd); + BUG_ON(!qtd); + } + + if (qtd) + enqueue_an_INT_packet(usb_hcd, qh, qtd); + + skip_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + } +} + +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) +static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb, + gfp_t flags) +{ + struct isp1760_qh *qh; + int is_input, type; + + qh = isp1760_qh_alloc(priv, flags); + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + is_input = usb_pipein(urb->pipe); + type = usb_pipetype(urb->pipe); + + if (type == PIPE_INTERRUPT) { + + if (urb->dev->speed == USB_SPEED_HIGH) { + + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { + /* NOTE interval 2 or 4 uframes could work. + * But interval 1 scheduling is simpler, and + * includes high bandwidth. + */ + printk(KERN_ERR "intr period %d uframes, NYET!", + urb->interval); + qh_destroy(qh); + return NULL; + } + } else { + qh->period = urb->interval; + } + } + + /* support for tt scheduling, and access to toggles */ + qh->dev = urb->dev; + + if (!usb_pipecontrol(urb->pipe)) + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, + 1); + return qh; +} + +/* + * For control/bulk/interrupt, return QH with these TDs appended. + * Allocates and initializes the QH if necessary. + * Returns null if it can't allocate a QH it needs to. + * If the QH has TDs (urbs) already, that's great. + */ +static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv, + struct urb *urb, struct list_head *qtd_list, int epnum, + void **ptr) +{ + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; + struct isp1760_qtd *prev_qtd; + + qh = (struct isp1760_qh *)*ptr; + if (!qh) { + /* can't sleep here, we have priv->lock... */ + qh = qh_make(priv, urb, GFP_ATOMIC); + if (!qh) + return qh; + *ptr = qh; + } + + qtd = list_entry(qtd_list->next, struct isp1760_qtd, + qtd_list); + if (!list_empty(&qh->qtd_list)) + prev_qtd = list_entry(qh->qtd_list.prev, + struct isp1760_qtd, qtd_list); + else + prev_qtd = NULL; + + list_splice(qtd_list, qh->qtd_list.prev); + if (prev_qtd) { + BUG_ON(prev_qtd->hw_next); + prev_qtd->hw_next = qtd; + } + + urb->hcpriv = qh; + return qh; +} + +static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb, + struct list_head *qtd_list) +{ + struct list_head *entry, *temp; + + list_for_each_safe(entry, temp, qtd_list) { + struct isp1760_qtd *qtd; + + qtd = list_entry(entry, struct isp1760_qtd, qtd_list); + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + } +} + +static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb, + struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p) +{ + struct isp1760_qtd *qtd; + int epnum; + unsigned long flags; + struct isp1760_qh *qh = NULL; + int rc; + int qh_busy; + + qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list); + epnum = urb->ep->desc.bEndpointAddress; + + spin_lock_irqsave(&priv->lock, flags); + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) { + rc = -ESHUTDOWN; + goto done; + } + rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb); + if (rc) + goto done; + + qh = urb->ep->hcpriv; + if (qh) + qh_busy = !list_empty(&qh->qtd_list); + else + qh_busy = 0; + + qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv); + if (!qh) { + usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); + rc = -ENOMEM; + goto done; + } + + if (!qh_busy) + p(priv_to_hcd(priv), qh, qtd); + +done: + spin_unlock_irqrestore(&priv->lock, flags); + if (!qh) + qtd_list_free(priv, urb, qtd_list); + return rc; +} + +static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv, + gfp_t flags) +{ + struct isp1760_qtd *qtd; + + qtd = kmem_cache_zalloc(qtd_cachep, flags); + if (qtd) + INIT_LIST_HEAD(&qtd->qtd_list); + + return qtd; +} + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv, + struct urb *urb, struct list_head *head, gfp_t flags) +{ + struct isp1760_qtd *qtd, *qtd_prev; + void *buf; + int len, maxpacket; + int is_input; + u32 token; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + return NULL; + + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + urb->status = -EINPROGRESS; + + token = 0; + /* for split transactions, SplitXState initialized to zero */ + + len = urb->transfer_buffer_length; + is_input = usb_pipein(urb->pipe); + if (usb_pipecontrol(urb->pipe)) { + /* SETUP pid */ + qtd_fill(qtd, urb->setup_packet, + sizeof(struct usb_ctrlrequest), + token | SETUP_PID); + + /* ... and always at least one more pid */ + token ^= DATA_TOGGLE; + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + + /* for zero length DATA stages, STATUS is always IN */ + if (len == 0) + token |= IN_PID; + } + + /* + * data transfer stage: buffer setup + */ + buf = urb->transfer_buffer; + + if (is_input) + token |= IN_PID; + else + token |= OUT_PID; + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + if (!buf && len) { + /* XXX This looks like usb storage / SCSI bug */ + printk(KERN_ERR "buf is null, dma is %08lx len is %d\n", + (long unsigned)urb->transfer_dma, len); + WARN_ON(1); + } + + this_qtd_len = qtd_fill(qtd, buf, len, token); + len -= this_qtd_len; + buf += this_qtd_len; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= DATA_TOGGLE; + + if (len <= 0) + break; + + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + } + + /* + * control requests may need a terminating data "status" ack; + * bulk ones may need a terminating short packet (zero length). + */ + if (urb->transfer_buffer_length != 0) { + int one_more = 0; + + if (usb_pipecontrol(urb->pipe)) { + one_more = 1; + /* "in" <--> "out" */ + token ^= IN_PID; + /* force DATA1 */ + token |= DATA_TOGGLE; + } else if (usb_pipebulk(urb->pipe) + && (urb->transfer_flags & URB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill(qtd, NULL, 0, token); + } + } + + qtd->status = URB_COMPLETE_NOTIFY; + return head; + +cleanup: + qtd_list_free(priv, urb, head); + return NULL; +} + +static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct list_head qtd_list; + packet_enqueue *pe; + + INIT_LIST_HEAD(&qtd_list); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + case PIPE_BULK: + + if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) + return -ENOMEM; + pe = enqueue_an_ATL_packet; + break; + + case PIPE_INTERRUPT: + if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) + return -ENOMEM; + pe = enqueue_an_INT_packet; + break; + + case PIPE_ISOCHRONOUS: + printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n"); + default: + return -EPIPE; + } + + isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe); + return 0; +} + +static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct inter_packet_info *ints; + u32 i; + u32 reg_base, or_reg, skip_reg; + int flags; + struct ptd ptd; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + return -EPIPE; + break; + + case PIPE_INTERRUPT: + ints = priv->int_ints; + reg_base = INT_REGS_OFFSET; + or_reg = HC_INT_IRQ_MASK_OR_REG; + skip_reg = HC_INT_PTD_SKIPMAP_REG; + break; + + default: + ints = priv->atl_ints; + reg_base = ATL_REGS_OFFSET; + or_reg = HC_ATL_IRQ_MASK_OR_REG; + skip_reg = HC_ATL_PTD_SKIPMAP_REG; + break; + } + + memset(&ptd, 0, sizeof(ptd)); + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < 32; i++) { + if (ints->urb == urb) { + u32 skip_map; + u32 or_map; + struct isp1760_qtd *qtd; + + skip_map = isp1760_readl(hcd->regs + skip_reg); + skip_map |= 1 << i; + isp1760_writel(skip_map, hcd->regs + skip_reg); + + or_map = isp1760_readl(hcd->regs + or_reg); + or_map &= ~(1 << i); + isp1760_writel(or_map, hcd->regs + or_reg); + + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base + + i * sizeof(ptd), sizeof(ptd)); + qtd = ints->qtd; + + clean_up_qtdlist(qtd); + + free_mem(priv, ints->payload); + + ints->urb = NULL; + ints->qh = NULL; + ints->qtd = NULL; + ints->data_buffer = NULL; + ints->payload = 0; + + isp1760_urb_done(priv, urb, status); + break; + } + ints++; + } + + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 imask; + irqreturn_t irqret = IRQ_NONE; + + spin_lock(&priv->lock); + + if (!(usb_hcd->state & HC_STATE_RUNNING)) + goto leave; + + imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG); + if (unlikely(!imask)) + goto leave; + + isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG); + if (imask & HC_ATL_INT) + do_atl_int(usb_hcd); + + if (imask & HC_INTL_INT) + do_intl_int(usb_hcd); + + irqret = IRQ_HANDLED; +leave: + spin_unlock(&priv->lock); + return irqret; +} + +static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 temp, status = 0; + u32 mask; + int retval = 1; + unsigned long flags; + + /* if !USB_SUSPEND, root hub timers won't get shut down ... */ + if (!HC_IS_RUNNING(hcd->state)) + return 0; + + /* init status to no-changes */ + buf[0] = 0; + mask = PORT_CSC; + + spin_lock_irqsave(&priv->lock, flags); + temp = isp1760_readl(hcd->regs + HC_PORTSC1); + + if (temp & PORT_OWNER) { + if (temp & PORT_CSC) { + temp &= ~PORT_CSC; + isp1760_writel(temp, hcd->regs + HC_PORTSC1); + goto done; + } + } + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + + if ((temp & mask) != 0 + || ((temp & PORT_RESUME) != 0 + && time_after_eq(jiffies, + priv->reset_done))) { + buf [0] |= 1 << (0 + 1); + status = STS_PCD; + } + /* FIXME autosuspend idle root hubs */ +done: + spin_unlock_irqrestore(&priv->lock, flags); + return status ? retval : 0; +} + +static void isp1760_hub_descriptor(struct isp1760_hcd *priv, + struct usb_hub_descriptor *desc) +{ + int ports = HCS_N_PORTS(priv->hcs_params); + u16 temp; + + desc->bDescriptorType = 0x29; + /* priv 1.0, 2.3.9 says 20ms max */ + desc->bPwrOn2PwrGood = 10; + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->bitmap[0], 0, temp); + memset(&desc->bitmap[temp], 0xff, temp); + + /* per-port overcurrent reporting */ + temp = 0x0008; + if (HCS_PPC(priv->hcs_params)) + /* per-port power control */ + temp |= 0x0001; + else + /* no power switching */ + temp |= 0x0002; + desc->wHubCharacteristics = cpu_to_le16(temp); +} + +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) + +static int check_reset_complete(struct isp1760_hcd *priv, int index, + u32 __iomem *status_reg, int port_status) +{ + if (!(port_status & PORT_CONNECT)) + return port_status; + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + + printk(KERN_ERR "port %d full speed --> companion\n", + index + 1); + + port_status |= PORT_OWNER; + port_status &= ~PORT_RWC_BITS; + isp1760_writel(port_status, status_reg); + + } else + printk(KERN_ERR "port %d high speed\n", index + 1); + + return port_status; +} + +static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, + u16 wValue, u16 wIndex, char *buf, u16 wLength) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int ports = HCS_N_PORTS(priv->hcs_params); + u32 __iomem *status_reg = hcd->regs + HC_PORTSC1; + u32 temp, status; + unsigned long flags; + int retval = 0; + unsigned selector; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave(&priv->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = isp1760_readl(status_reg); + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_FEAT_C_CONNECTION). + */ + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + isp1760_writel(temp & ~PORT_PE, status_reg); + break; + case USB_PORT_FEAT_C_ENABLE: + /* XXX error? */ + break; + case USB_PORT_FEAT_SUSPEND: + if (temp & PORT_RESET) + goto error; + + if (temp & PORT_SUSPEND) { + if ((temp & PORT_PE) == 0) + goto error; + /* resume signaling for 20 msec */ + temp &= ~(PORT_RWC_BITS); + isp1760_writel(temp | PORT_RESUME, + status_reg); + priv->reset_done = jiffies + + msecs_to_jiffies(20); + } + break; + case USB_PORT_FEAT_C_SUSPEND: + /* we auto-clear this feature */ + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(priv->hcs_params)) + isp1760_writel(temp & ~PORT_POWER, status_reg); + break; + case USB_PORT_FEAT_C_CONNECTION: + isp1760_writel(temp | PORT_CSC, + status_reg); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + /* XXX error ?*/ + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + isp1760_readl(hcd->regs + HC_USBCMD); + break; + case GetHubDescriptor: + isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset(buf, 0, 4); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + temp = isp1760_readl(status_reg); + + /* wPortChange bits */ + if (temp & PORT_CSC) + status |= 1 << USB_PORT_FEAT_C_CONNECTION; + + + /* whoever resumes must GetPortStatus to complete it!! */ + if (temp & PORT_RESUME) { + printk(KERN_ERR "Port resume should be skipped.\n"); + + /* Remote Wakeup received? */ + if (!priv->reset_done) { + /* resume signaling for 20 msec */ + priv->reset_done = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&priv_to_hcd(priv)->rh_timer, + priv->reset_done); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + priv->reset_done)) { + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + priv->reset_done = 0; + + /* stop resume signaling */ + temp = isp1760_readl(status_reg); + isp1760_writel( + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + retval = handshake(priv, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + isp1760_err(priv, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + } + } + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && time_after_eq(jiffies, + priv->reset_done)) { + status |= 1 << USB_PORT_FEAT_C_RESET; + priv->reset_done = 0; + + /* force reset to complete */ + isp1760_writel(temp & ~PORT_RESET, + status_reg); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(priv, status_reg, + PORT_RESET, 0, 750); + if (retval != 0) { + isp1760_err(priv, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } + + /* see what we found out */ + temp = check_reset_complete(priv, wIndex, status_reg, + isp1760_readl(status_reg)); + } + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_OWNER) + printk(KERN_ERR "Warning: PORT_OWNER is set\n"); + + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + /* status may be from integrated TT */ + status |= ehci_port_speed(priv, temp); + } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & (PORT_SUSPEND|PORT_RESUME)) + status |= 1 << USB_PORT_FEAT_SUSPEND; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; + + put_unaligned(cpu_to_le32(status), (__le32 *) buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = isp1760_readl(status_reg); + if (temp & PORT_OWNER) + break; + +/* temp &= ~PORT_RWC_BITS; */ + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + isp1760_writel(temp | PORT_PE, status_reg); + break; + + case USB_PORT_FEAT_SUSPEND: + if ((temp & PORT_PE) == 0 + || (temp & PORT_RESET) != 0) + goto error; + + isp1760_writel(temp | PORT_SUSPEND, status_reg); + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(priv->hcs_params)) + isp1760_writel(temp | PORT_POWER, + status_reg); + break; + case USB_PORT_FEAT_RESET: + if (temp & PORT_RESUME) + goto error; + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ + if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && PORT_USB11(temp)) { + temp |= PORT_OWNER; + } else { + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + priv->reset_done = jiffies + + msecs_to_jiffies(50); + } + isp1760_writel(temp, status_reg); + break; + default: + goto error; + } + isp1760_readl(hcd->regs + HC_USBCMD); + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&priv->lock, flags); + return retval; +} + +static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd, + struct usb_host_endpoint *ep) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; + u32 flags; + + spin_lock_irqsave(&priv->lock, flags); + qh = ep->hcpriv; + if (!qh) + goto out; + + ep->hcpriv = NULL; + do { + /* more than entry might get removed */ + if (list_empty(&qh->qtd_list)) + break; + + qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd, + qtd_list); + + if (qtd->status & URB_ENQUEUED) { + + spin_unlock_irqrestore(&priv->lock, flags); + isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET); + spin_lock_irqsave(&priv->lock, flags); + } else { + struct urb *urb; + + urb = qtd->urb; + clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, -ECONNRESET); + } + } while (1); + + qh_destroy(qh); + /* remove requests and leak them. + * ATL are pretty fast done, INT could take a while... + * The latter shoule be removed + */ +out: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int isp1760_get_frame(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 fr; + + fr = isp1760_readl(hcd->regs + HC_FRINDEX); + return (fr >> 3) % priv->periodic_size; +} + +static void isp1760_stop(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, + NULL, 0); + mdelay(20); + + spin_lock_irq(&priv->lock); + ehci_reset(priv); + /* Disable IRQ */ + isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); + spin_unlock_irq(&priv->lock); + + isp1760_writel(0, hcd->regs + HC_CONFIGFLAG); +} + +static void isp1760_shutdown(struct usb_hcd *hcd) +{ + u32 command; + + isp1760_stop(hcd); + isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); + + command = isp1760_readl(hcd->regs + HC_USBCMD); + command &= ~CMD_RUN; + isp1760_writel(command, hcd->regs + HC_USBCMD); +} + +static const struct hc_driver isp1760_hc_driver = { + .description = "isp1760-hcd", + .product_desc = "NXP ISP1760 USB Host Controller", + .hcd_priv_size = sizeof(struct isp1760_hcd), + .irq = isp1760_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = isp1760_hc_setup, + .start = isp1760_run, + .stop = isp1760_stop, + .shutdown = isp1760_shutdown, + .urb_enqueue = isp1760_urb_enqueue, + .urb_dequeue = isp1760_urb_dequeue, + .endpoint_disable = isp1760_endpoint_disable, + .get_frame_number = isp1760_get_frame, + .hub_status_data = isp1760_hub_status_data, + .hub_control = isp1760_hub_control, +}; + +int __init init_kmem_once(void) +{ + qtd_cachep = kmem_cache_create("isp1760_qtd", + sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY | + SLAB_MEM_SPREAD, NULL); + + if (!qtd_cachep) + return -ENOMEM; + + qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh), + 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); + + if (!qh_cachep) { + kmem_cache_destroy(qtd_cachep); + return -ENOMEM; + } + + return 0; +} + +void deinit_kmem_cache(void) +{ + kmem_cache_destroy(qtd_cachep); + kmem_cache_destroy(qh_cachep); +} + +struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, + u64 irqflags, struct device *dev, const char *busname) +{ + struct usb_hcd *hcd; + struct isp1760_hcd *priv; + int ret; + + if (usb_disabled()) + return ERR_PTR(-ENODEV); + + /* prevent usb-core allocating DMA pages */ + dev->dma_mask = NULL; + + hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id); + if (!hcd) + return ERR_PTR(-ENOMEM); + + priv = hcd_to_priv(hcd); + init_memory(priv); + hcd->regs = ioremap(res_start, res_len); + if (!hcd->regs) { + ret = -EIO; + goto err_put; + } + + ret = usb_add_hcd(hcd, irq, irqflags); + if (ret) + goto err_unmap; + + hcd->irq = irq; + hcd->rsrc_start = res_start; + hcd->rsrc_len = res_len; + + return hcd; + +err_unmap: + iounmap(hcd->regs); + +err_put: + usb_put_hcd(hcd); + + return ERR_PTR(ret); +} + +MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP"); +MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h new file mode 100644 index 000000000000..3d86d0f6b147 --- /dev/null +++ b/drivers/usb/host/isp1760-hcd.h @@ -0,0 +1,206 @@ +#ifndef _ISP1760_HCD_H_ +#define _ISP1760_HCD_H_ + +/* exports for if */ +struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, + u64 irqflags, struct device *dev, const char *busname); +int init_kmem_once(void); +void deinit_kmem_cache(void); + +/* EHCI capability registers */ +#define HC_CAPLENGTH 0x00 +#define HC_HCSPARAMS 0x04 +#define HC_HCCPARAMS 0x08 + +/* EHCI operational registers */ +#define HC_USBCMD 0x20 +#define HC_USBSTS 0x24 +#define HC_FRINDEX 0x2c +#define HC_CONFIGFLAG 0x60 +#define HC_PORTSC1 0x64 +#define HC_ISO_PTD_DONEMAP_REG 0x130 +#define HC_ISO_PTD_SKIPMAP_REG 0x134 +#define HC_ISO_PTD_LASTPTD_REG 0x138 +#define HC_INT_PTD_DONEMAP_REG 0x140 +#define HC_INT_PTD_SKIPMAP_REG 0x144 +#define HC_INT_PTD_LASTPTD_REG 0x148 +#define HC_ATL_PTD_DONEMAP_REG 0x150 +#define HC_ATL_PTD_SKIPMAP_REG 0x154 +#define HC_ATL_PTD_LASTPTD_REG 0x158 + +/* Configuration Register */ +#define HC_HW_MODE_CTRL 0x300 +#define ALL_ATX_RESET (1 << 31) +#define HW_DATA_BUS_32BIT (1 << 8) +#define HW_DACK_POL_HIGH (1 << 6) +#define HW_DREQ_POL_HIGH (1 << 5) +#define HW_INTR_HIGH_ACT (1 << 2) +#define HW_INTR_EDGE_TRIG (1 << 1) +#define HW_GLOBAL_INTR_EN (1 << 0) + +#define HC_CHIP_ID_REG 0x304 +#define HC_SCRATCH_REG 0x308 + +#define HC_RESET_REG 0x30c +#define SW_RESET_RESET_HC (1 << 1) +#define SW_RESET_RESET_ALL (1 << 0) + +#define HC_BUFFER_STATUS_REG 0x334 +#define ATL_BUFFER 0x1 +#define INT_BUFFER 0x2 +#define ISO_BUFFER 0x4 +#define BUFFER_MAP 0x7 + +#define HC_MEMORY_REG 0x33c +#define HC_PORT1_CTRL 0x374 +#define PORT1_POWER (3 << 3) +#define PORT1_INIT1 (1 << 7) +#define PORT1_INIT2 (1 << 23) + +/* Interrupt Register */ +#define HC_INTERRUPT_REG 0x310 + +#define HC_INTERRUPT_ENABLE 0x314 +#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT) +#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT) + +#define HC_ISO_INT (1 << 9) +#define HC_ATL_INT (1 << 8) +#define HC_INTL_INT (1 << 7) +#define HC_EOT_INT (1 << 3) +#define HC_SOT_INT (1 << 1) + +#define HC_ISO_IRQ_MASK_OR_REG 0x318 +#define HC_INT_IRQ_MASK_OR_REG 0x31C +#define HC_ATL_IRQ_MASK_OR_REG 0x320 +#define HC_ISO_IRQ_MASK_AND_REG 0x324 +#define HC_INT_IRQ_MASK_AND_REG 0x328 +#define HC_ATL_IRQ_MASK_AND_REG 0x32C + +/* Register sets */ +#define HC_BEGIN_OF_ATL 0x0c00 +#define HC_BEGIN_OF_INT 0x0800 +#define HC_BEGIN_OF_ISO 0x0400 +#define HC_BEGIN_OF_PAYLOAD 0x1000 + +/* urb state*/ +#define DELETE_URB (0x0008) +#define NO_TRANSFER_ACTIVE (0xffffffff) + +#define ATL_REGS_OFFSET (0xc00) +#define INT_REGS_OFFSET (0x800) + +/* Philips Transfer Descriptor (PTD) */ +struct ptd { + __le32 dw0; + __le32 dw1; + __le32 dw2; + __le32 dw3; + __le32 dw4; + __le32 dw5; + __le32 dw6; + __le32 dw7; +}; + +struct inter_packet_info { + void *data_buffer; + u32 payload; +#define PTD_FIRE_NEXT (1 << 0) +#define PTD_URB_FINISHED (1 << 1) + struct urb *urb; + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; +}; + + +typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd); + +#define isp1760_info(priv, fmt, args...) \ + dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args) + +#define isp1760_err(priv, fmt, args...) \ + dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args) + +/* chip memory management */ +struct memory_chunk { + unsigned int start; + unsigned int size; + unsigned int free; +}; + +/* + * 60kb divided in: + * - 32 blocks @ 256 bytes + * - 20 blocks @ 1024 bytes + * - 4 blocks @ 8192 bytes + */ + +#define BLOCK_1_NUM 32 +#define BLOCK_2_NUM 20 +#define BLOCK_3_NUM 4 + +#define BLOCK_1_SIZE 256 +#define BLOCK_2_SIZE 1024 +#define BLOCK_3_SIZE 8192 +#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM) +#define PAYLOAD_SIZE 0xf000 + +/* I saw if some reloads if the pointer was negative */ +#define ISP1760_NULL_POINTER (0x400) + +/* ATL */ +/* DW0 */ +#define PTD_VALID 1 +#define PTD_LENGTH(x) (((u32) x) << 3) +#define PTD_MAXPACKET(x) (((u32) x) << 18) +#define PTD_MULTI(x) (((u32) x) << 29) +#define PTD_ENDPOINT(x) (((u32) x) << 31) +/* DW1 */ +#define PTD_DEVICE_ADDR(x) (((u32) x) << 3) +#define PTD_PID_TOKEN(x) (((u32) x) << 10) +#define PTD_TRANS_BULK ((u32) 2 << 12) +#define PTD_TRANS_INT ((u32) 3 << 12) +#define PTD_TRANS_SPLIT ((u32) 1 << 14) +#define PTD_SE_USB_LOSPEED ((u32) 2 << 16) +#define PTD_PORT_NUM(x) (((u32) x) << 18) +#define PTD_HUB_NUM(x) (((u32) x) << 25) +#define PTD_PING(x) (((u32) x) << 26) +/* DW2 */ +#define PTD_RL_CNT(x) (((u32) x) << 25) +#define PTD_DATA_START_ADDR(x) (((u32) x) << 8) +#define BASE_ADDR 0x1000 +/* DW3 */ +#define PTD_CERR(x) (((u32) x) << 23) +#define PTD_NAC_CNT(x) (((u32) x) << 19) +#define PTD_ACTIVE ((u32) 1 << 31) +#define PTD_DATA_TOGGLE(x) (((u32) x) << 25) + +#define DW3_HALT_BIT (1 << 30) +#define DW3_ERROR_BIT (1 << 28) +#define DW3_QTD_ACTIVE (1 << 31) + +#define INT_UNDERRUN (1 << 2) +#define INT_BABBLE (1 << 1) +#define INT_EXACT (1 << 0) + +#define DW1_GET_PID(x) (((x) >> 10) & 0x3) +#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff) +#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff) + +#define SETUP_PID (2) +#define IN_PID (1) +#define OUT_PID (0) +#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3) + +#define DATA_TOGGLE (1 << 31) +#define GET_DATA_TOGGLE(x) ((x) >> 31) + +/* Errata 1 */ +#define RL_COUNTER (0) +#define NAK_COUNTER (0) +#define ERR_COUNTER (2) + +#define HC_ATL_PL_SIZE (8192) + +#endif diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c new file mode 100644 index 000000000000..73fb2a38f1e4 --- /dev/null +++ b/drivers/usb/host/isp1760-if.c @@ -0,0 +1,298 @@ +/* + * Glue code for the ISP1760 driver and bus + * Currently there is support for + * - OpenFirmware + * - PCI + * + * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> + * + */ + +#include <linux/usb.h> +#include <linux/io.h> + +#include "../core/hcd.h" +#include "isp1760-hcd.h" + +#ifdef CONFIG_USB_ISP1760_OF +#include <linux/of.h> +#include <linux/of_platform.h> +#endif + +#ifdef CONFIG_USB_ISP1760_PCI +#include <linux/pci.h> +#endif + +#ifdef CONFIG_USB_ISP1760_OF +static int of_isp1760_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct usb_hcd *hcd; + struct device_node *dp = dev->node; + struct resource *res; + struct resource memory; + struct of_irq oirq; + int virq; + u64 res_len; + int ret; + + ret = of_address_to_resource(dp, 0, &memory); + if (ret) + return -ENXIO; + + res = request_mem_region(memory.start, memory.end - memory.start + 1, + dev->dev.bus_id); + if (!res) + return -EBUSY; + + res_len = memory.end - memory.start + 1; + + if (of_irq_map_one(dp, 0, &oirq)) { + ret = -ENODEV; + goto release_reg; + } + + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + + hcd = isp1760_register(memory.start, res_len, virq, + IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); + if (IS_ERR(hcd)) { + ret = PTR_ERR(hcd); + goto release_reg; + } + + dev_set_drvdata(&dev->dev, hcd); + return ret; + +release_reg: + release_mem_region(memory.start, memory.end - memory.start + 1); + return ret; +} + +static int of_isp1760_remove(struct of_device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); + + dev_set_drvdata(&dev->dev, NULL); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + return 0; +} + +static struct of_device_id of_isp1760_match[] = { + { + .compatible = "nxp,usb-isp1760", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_isp1760_match); + +static struct of_platform_driver isp1760_of_driver = { + .name = "nxp-isp1760", + .match_table = of_isp1760_match, + .probe = of_isp1760_probe, + .remove = of_isp1760_remove, +}; +#endif + +#ifdef CONFIG_USB_ISP1760_PCI +static u32 nxp_pci_io_base; +static u32 iolength; +static u32 pci_mem_phy0; +static u32 length; +static u8 *chip_addr; +static u8 *iobase; + +static int __devinit isp1761_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u8 latency, limit; + __u32 reg_data; + int retry_count; + int length; + int status = 1; + struct usb_hcd *hcd; + + if (usb_disabled()) + return -ENODEV; + + if (pci_enable_device(dev) < 0) + return -ENODEV; + + if (!dev->irq) + return -ENODEV; + + /* Grab the PLX PCI mem maped port start address we need */ + nxp_pci_io_base = pci_resource_start(dev, 0); + iolength = pci_resource_len(dev, 0); + + if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { + printk(KERN_ERR "request region #1\n"); + return -EBUSY; + } + + iobase = ioremap_nocache(nxp_pci_io_base, iolength); + if (!iobase) { + printk(KERN_ERR "ioremap #1\n"); + release_mem_region(nxp_pci_io_base, iolength); + return -ENOMEM; + } + /* Grab the PLX PCI shared memory of the ISP 1761 we need */ + pci_mem_phy0 = pci_resource_start(dev, 3); + length = pci_resource_len(dev, 3); + + if (length < 0xffff) { + printk(KERN_ERR "memory length for this resource is less than " + "required\n"); + release_mem_region(nxp_pci_io_base, iolength); + iounmap(iobase); + return -ENOMEM; + } + + if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) { + printk(KERN_ERR "host controller already in use\n"); + release_mem_region(nxp_pci_io_base, iolength); + iounmap(iobase); + return -EBUSY; + } + + /* bad pci latencies can contribute to overruns */ + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte(dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); + } + + /* Try to check whether we can access Scratch Register of + * Host Controller or not. The initial PCI access is retried until + * local init for the PCI bridge is completed + */ + retry_count = 20; + reg_data = 0; + while ((reg_data != 0xFACE) && retry_count) { + /*by default host is in 16bit mode, so + * io operations at this stage must be 16 bit + * */ + writel(0xface, chip_addr + HC_SCRATCH_REG); + udelay(100); + reg_data = readl(chip_addr + HC_SCRATCH_REG); + retry_count--; + } + + /* Host Controller presence is detected by writing to scratch register + * and reading back and checking the contents are same or not + */ + if (reg_data != 0xFACE) { + err("scratch register mismatch %x", reg_data); + goto clean; + } + + pci_set_master(dev); + + status = readl(iobase + 0x68); + status |= 0x900; + writel(status, iobase + 0x68); + + dev->dev.dma_mask = NULL; + hcd = isp1760_register(pci_mem_phy0, length, dev->irq, + IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); + pci_set_drvdata(dev, hcd); + if (!hcd) + return 0; +clean: + status = -ENODEV; + iounmap(iobase); + release_mem_region(pci_mem_phy0, length); + release_mem_region(nxp_pci_io_base, iolength); + return status; +} +static void isp1761_pci_remove(struct pci_dev *dev) +{ + struct usb_hcd *hcd; + + hcd = pci_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + pci_disable_device(dev); + + iounmap(iobase); + iounmap(chip_addr); + + release_mem_region(nxp_pci_io_base, iolength); + release_mem_region(pci_mem_phy0, length); +} + +static void isp1761_pci_shutdown(struct pci_dev *dev) +{ + printk(KERN_ERR "ips1761_pci_shutdown\n"); +} + +static const struct pci_device_id isp1760_plx [] = { { + /* handle any USB 2.0 EHCI controller */ + PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0), + .driver_data = 0, +}, +{ /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, isp1760_plx); + +static struct pci_driver isp1761_pci_driver = { + .name = "isp1760", + .id_table = isp1760_plx, + .probe = isp1761_pci_probe, + .remove = isp1761_pci_remove, + .shutdown = isp1761_pci_shutdown, +}; +#endif + +static int __init isp1760_init(void) +{ + int ret; + + init_kmem_once(); + +#ifdef CONFIG_USB_ISP1760_OF + ret = of_register_platform_driver(&isp1760_of_driver); + if (ret) { + deinit_kmem_cache(); + return ret; + } +#endif +#ifdef CONFIG_USB_ISP1760_PCI + ret = pci_register_driver(&isp1761_pci_driver); + if (ret) + goto unreg_of; +#endif + return ret; + +#ifdef CONFIG_USB_ISP1760_PCI +unreg_of: +#endif +#ifdef CONFIG_USB_ISP1760_OF + of_unregister_platform_driver(&isp1760_of_driver); +#endif + deinit_kmem_cache(); + return ret; +} +module_init(isp1760_init); + +static void __exit isp1760_exit(void) +{ +#ifdef CONFIG_USB_ISP1760_OF + of_unregister_platform_driver(&isp1760_of_driver); +#endif +#ifdef CONFIG_USB_ISP1760_PCI + pci_unregister_driver(&isp1761_pci_driver); +#endif + deinit_kmem_cache(); +} +module_exit(isp1760_exit); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 5be3bb3e6a9d..79a78029f896 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -613,7 +613,7 @@ static void start_hnp(struct ohci_hcd *ohci); static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) { __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; - u32 temp; + u32 temp = 0; u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); u16 reset_done = now + PORT_RESET_MSEC; int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC); @@ -736,14 +736,14 @@ static int ohci_hub_control ( break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index f4fa93dabdde..16667342b3c3 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -993,7 +993,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, struct r8a66597_td *td) { int i; - u16 *p = (u16 *)td->urb->setup_packet; + __le16 *p = (__le16 *)td->urb->setup_packet; unsigned long setup_addr = USBREQ; r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket, @@ -1001,7 +1001,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); + r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -2131,7 +2131,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = cpu_to_le32(rh->port); + *(__le32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 274276cf8621..426575247b23 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1100,7 +1100,7 @@ sl811h_hub_descriptor ( /* no overcurrent errors detection/handling */ temp |= 0x0010; - desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp); + desc->wHubCharacteristics = cpu_to_le16(temp); /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ desc->bitmap[0] = 0 << 1; @@ -1506,15 +1506,7 @@ static const char proc_filename[] = "driver/sl811h"; static void create_debug_file(struct sl811 *sl811) { - struct proc_dir_entry *pde; - - pde = create_proc_entry(proc_filename, 0, NULL); - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = sl811; - sl811->pde = pde; + sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); } static void remove_debug_file(struct sl811 *sl811) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d3e0d8aa3980..3a7bfe7a8874 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) return 0; } -static int remote_wakeup_is_broken(struct uhci_hcd *uhci) +static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) { int port; const char *sys_info; @@ -261,27 +261,60 @@ __releases(uhci->lock) __acquires(uhci->lock) { int auto_stop; - int int_enable, egsm_enable; + int int_enable, egsm_enable, wakeup_enable; struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub; auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); dev_dbg(&rhdev->dev, "%s%s\n", __func__, (auto_stop ? " (auto-stop)" : "")); - /* Enable resume-detect interrupts if they work. - * Then enter Global Suspend mode if _it_ works, still configured. + /* Start off by assuming Resume-Detect interrupts and EGSM work + * and that remote wakeups should be enabled. */ egsm_enable = USBCMD_EGSM; - uhci->working_RD = 1; + uhci->RD_enable = 1; int_enable = USBINTR_RESUME; - if (remote_wakeup_is_broken(uhci)) - egsm_enable = 0; - if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable || + wakeup_enable = 1; + + /* In auto-stop mode wakeups must always be detected, but + * Resume-Detect interrupts may be prohibited. (In the absence + * of CONFIG_PM, they are always disallowed.) + */ + if (auto_stop) { + if (!device_may_wakeup(&rhdev->dev)) + int_enable = 0; + + /* In bus-suspend mode wakeups may be disabled, but if they are + * allowed then so are Resume-Detect interrupts. + */ + } else { #ifdef CONFIG_PM - (!auto_stop && !rhdev->do_remote_wakeup) || + if (!rhdev->do_remote_wakeup) + wakeup_enable = 0; #endif - (auto_stop && !device_may_wakeup(&rhdev->dev))) - uhci->working_RD = int_enable = 0; + } + + /* EGSM causes the root hub to echo a 'K' signal (resume) out any + * port which requests a remote wakeup. According to the USB spec, + * every hub is supposed to do this. But if we are ignoring + * remote-wakeup requests anyway then there's no point to it. + * We also shouldn't enable EGSM if it's broken. + */ + if (!wakeup_enable || global_suspend_mode_is_broken(uhci)) + egsm_enable = 0; + + /* If we're ignoring wakeup events then there's no reason to + * enable Resume-Detect interrupts. We also shouldn't enable + * them if they are broken or disallowed. + * + * This logic may lead us to enabling RD but not EGSM. The UHCI + * spec foolishly says that RD works only when EGSM is on, but + * there's no harm in enabling it anyway -- perhaps some chips + * will implement it! + */ + if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) || + !int_enable) + uhci->RD_enable = int_enable = 0; outw(int_enable, uhci->io_addr + USBINTR); outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); @@ -308,7 +341,11 @@ __acquires(uhci->lock) uhci->rh_state = new_state; uhci->is_stopped = UHCI_IS_STOPPED; - uhci_to_hcd(uhci)->poll_rh = !int_enable; + + /* If interrupts don't work and remote wakeup is enabled then + * the suspended root hub needs to be polled. + */ + uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable); uhci_scan_schedule(uhci); uhci_fsbr_off(uhci); @@ -344,9 +381,12 @@ __acquires(uhci->lock) * for 20 ms. */ if (uhci->rh_state == UHCI_RH_SUSPENDED) { + unsigned egsm; + + /* Keep EGSM on if it was set before */ + egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM; uhci->rh_state = UHCI_RH_RESUMING; - outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF, - uhci->io_addr + USBCMD); + outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD); spin_unlock_irq(&uhci->lock); msleep(20); spin_lock_irq(&uhci->lock); @@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd) spin_unlock_irq(&uhci->lock); - if (!uhci->working_RD) { - /* Suspended root hub needs to be polled */ + /* If interrupts don't work and remote wakeup is enabled then + * the suspended root hub needs to be polled. + */ + if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) { hcd->poll_rh = 1; usb_hcd_poll_rh_status(hcd); } diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 340d6ed3e6e9..7d01c5677f92 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -400,8 +400,9 @@ struct uhci_hcd { unsigned int scan_in_progress:1; /* Schedule scan is running */ unsigned int need_rescan:1; /* Redo the schedule scan */ unsigned int dead:1; /* Controller has died */ - unsigned int working_RD:1; /* Suspended root hub doesn't - need to be polled */ + unsigned int RD_enable:1; /* Suspended root hub with + Resume-Detect interrupts + enabled */ unsigned int is_initialized:1; /* Data structure is usable */ unsigned int fsbr_is_on:1; /* FSBR is turned on */ unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 11580e81e2c6..7aafd53fbcab 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -148,7 +148,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in /* Structure to hold all of our device specific stuff */ struct ld_usb { - struct semaphore sem; /* locks this structure */ + struct mutex mutex; /* locks this structure */ struct usb_interface* intf; /* save off the usb interface pointer */ int open_count; /* number of times this port has been opened */ @@ -319,7 +319,7 @@ static int ld_usb_open(struct inode *inode, struct file *file) return -ENODEV; /* lock this device */ - if (down_interruptible(&dev->sem)) + if (mutex_lock_interruptible(&dev->mutex)) return -ERESTARTSYS; /* allow opening only once */ @@ -358,7 +358,7 @@ static int ld_usb_open(struct inode *inode, struct file *file) file->private_data = dev; unlock_exit: - up(&dev->sem); + mutex_unlock(&dev->mutex); return retval; } @@ -378,7 +378,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) goto exit; } - if (down_interruptible(&dev->sem)) { + if (mutex_lock_interruptible(&dev->mutex)) { retval = -ERESTARTSYS; goto exit; } @@ -389,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) } if (dev->intf == NULL) { /* the device was unplugged before the file was released */ - up(&dev->sem); + mutex_unlock(&dev->mutex); /* unlock here as ld_usb_delete frees dev */ ld_usb_delete(dev); goto exit; @@ -402,7 +402,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) dev->open_count = 0; unlock_exit: - up(&dev->sem); + mutex_unlock(&dev->mutex); exit: return retval; @@ -448,7 +448,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, goto exit; /* lock this object */ - if (down_interruptible(&dev->sem)) { + if (mutex_lock_interruptible(&dev->mutex)) { retval = -ERESTARTSYS; goto exit; } @@ -505,7 +505,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, unlock_exit: /* unlock the device */ - up(&dev->sem); + mutex_unlock(&dev->mutex); exit: return retval; @@ -528,7 +528,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, goto exit; /* lock this object */ - if (down_interruptible(&dev->sem)) { + if (mutex_lock_interruptible(&dev->mutex)) { retval = -ERESTARTSYS; goto exit; } @@ -602,7 +602,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, unlock_exit: /* unlock the device */ - up(&dev->sem); + mutex_unlock(&dev->mutex); exit: return retval; @@ -651,7 +651,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * dev_err(&intf->dev, "Out of memory\n"); goto exit; } - init_MUTEX(&dev->sem); + mutex_init(&dev->mutex); spin_lock_init(&dev->rbsl); dev->intf = intf; init_waitqueue_head(&dev->read_wait); @@ -765,15 +765,15 @@ static void ld_usb_disconnect(struct usb_interface *intf) /* give back our minor */ usb_deregister_dev(intf, &ld_usb_class); - down(&dev->sem); + mutex_lock(&dev->mutex); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { - up(&dev->sem); + mutex_unlock(&dev->mutex); ld_usb_delete(dev); } else { dev->intf = NULL; - up(&dev->sem); + mutex_unlock(&dev->mutex); } dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index a51983854ca0..742be3c35947 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -79,30 +79,10 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test) /* set up all urbs so they can be used with either bulk or interrupt */ #define INTERRUPT_RATE 1 /* msec/transfer */ -#define xprintk(tdev,level,fmt,args...) \ - dev_printk(level , &(tdev)->intf->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define ERROR(tdev, fmt, args...) \ + dev_err(&(tdev)->intf->dev , fmt , ## args) +#define WARN(tdev, fmt, args...) \ + dev_warn(&(tdev)->intf->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -236,7 +216,7 @@ static struct urb *simple_alloc_urb ( static unsigned pattern = 0; module_param (pattern, uint, S_IRUGO); -// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)"); +MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)"); static inline void simple_fill_buf (struct urb *urb) { @@ -257,7 +237,7 @@ static inline void simple_fill_buf (struct urb *urb) } } -static inline int simple_check_buf (struct urb *urb) +static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb) { unsigned i; u8 expected; @@ -285,7 +265,7 @@ static inline int simple_check_buf (struct urb *urb) } if (*buf == expected) continue; - dbg ("buf[%d] = %d (not %d)", i, *buf, expected); + ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected); return -EINVAL; } return 0; @@ -299,6 +279,7 @@ static void simple_free_urb (struct urb *urb) } static int simple_io ( + struct usbtest_dev *tdev, struct urb *urb, int iterations, int vary, @@ -324,7 +305,7 @@ static int simple_io ( retval = urb->status; urb->dev = udev; if (retval == 0 && usb_pipein (urb->pipe)) - retval = simple_check_buf (urb); + retval = simple_check_buf(tdev, urb); if (vary) { int len = urb->transfer_buffer_length; @@ -341,7 +322,7 @@ static int simple_io ( urb->transfer_buffer_length = max; if (expected != retval) - dev_dbg (&udev->dev, + dev_err(&udev->dev, "%s failed, iterations left %d, status %d (not %d)\n", label, iterations, retval, expected); return retval; @@ -357,7 +338,7 @@ static int simple_io ( static void free_sglist (struct scatterlist *sg, int nents) { unsigned i; - + if (!sg) return; for (i = 0; i < nents; i++) { @@ -415,7 +396,7 @@ alloc_sglist (int nents, int max, int vary) } static int perform_sglist ( - struct usb_device *udev, + struct usbtest_dev *tdev, unsigned iterations, int pipe, struct usb_sg_request *req, @@ -423,6 +404,7 @@ static int perform_sglist ( int nents ) { + struct usb_device *udev = testdev_to_usbdev(tdev); int retval = 0; while (retval == 0 && iterations-- > 0) { @@ -431,7 +413,7 @@ static int perform_sglist ( ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE, sg, nents, 0, GFP_KERNEL); - + if (retval) break; usb_sg_wait (req); @@ -446,7 +428,8 @@ static int perform_sglist ( // failure if retval is as we expected ... if (retval) - dbg ("perform_sglist failed, iterations left %d, status %d", + ERROR(tdev, "perform_sglist failed, " + "iterations left %d, status %d\n", iterations, retval); return retval; } @@ -505,28 +488,28 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate) alternate); } -static int is_good_config (char *buf, int len) +static int is_good_config(struct usbtest_dev *tdev, int len) { struct usb_config_descriptor *config; - + if (len < sizeof *config) return 0; - config = (struct usb_config_descriptor *) buf; + config = (struct usb_config_descriptor *) tdev->buf; switch (config->bDescriptorType) { case USB_DT_CONFIG: case USB_DT_OTHER_SPEED_CONFIG: if (config->bLength != 9) { - dbg ("bogus config descriptor length"); + ERROR(tdev, "bogus config descriptor length\n"); return 0; } /* this bit 'must be 1' but often isn't */ if (!realworld && !(config->bmAttributes & 0x80)) { - dbg ("high bit of config attributes not set"); + ERROR(tdev, "high bit of config attributes not set\n"); return 0; } if (config->bmAttributes & 0x1f) { /* reserved == 0 */ - dbg ("reserved config bits set"); + ERROR(tdev, "reserved config bits set\n"); return 0; } break; @@ -538,7 +521,7 @@ static int is_good_config (char *buf, int len) return 1; if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */ return 1; - dbg ("bogus config descriptor read size"); + ERROR(tdev, "bogus config descriptor read size\n"); return 0; } @@ -571,7 +554,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) /* 9.2.3 constrains the range here */ alt = iface->altsetting [i].desc.bAlternateSetting; if (alt < 0 || alt >= iface->num_altsetting) { - dev_dbg (&iface->dev, + dev_err(&iface->dev, "invalid alt [%d].bAltSetting = %d\n", i, alt); } @@ -583,7 +566,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) /* [9.4.10] set_interface */ retval = set_altsetting (dev, alt); if (retval) { - dev_dbg (&iface->dev, "can't set_interface = %d, %d\n", + dev_err(&iface->dev, "can't set_interface = %d, %d\n", alt, retval); return retval; } @@ -591,7 +574,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) /* [9.4.4] get_interface always works */ retval = get_altsetting (dev); if (retval != alt) { - dev_dbg (&iface->dev, "get alt should be %d, was %d\n", + dev_err(&iface->dev, "get alt should be %d, was %d\n", alt, retval); return (retval < 0) ? retval : -EDOM; } @@ -611,7 +594,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) USB_DIR_IN | USB_RECIP_DEVICE, 0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT); if (retval != 1 || dev->buf [0] != expected) { - dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n", + dev_err(&iface->dev, "get config --> %d %d (1 %d)\n", retval, dev->buf[0], expected); return (retval < 0) ? retval : -EDOM; } @@ -621,7 +604,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0, dev->buf, sizeof udev->descriptor); if (retval != sizeof udev->descriptor) { - dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval); + dev_err(&iface->dev, "dev descriptor --> %d\n", retval); return (retval < 0) ? retval : -EDOM; } @@ -629,8 +612,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) for (i = 0; i < udev->descriptor.bNumConfigurations; i++) { retval = usb_get_descriptor (udev, USB_DT_CONFIG, i, dev->buf, TBUF_SIZE); - if (!is_good_config (dev->buf, retval)) { - dev_dbg (&iface->dev, + if (!is_good_config(dev, retval)) { + dev_err(&iface->dev, "config [%d] descriptor --> %d\n", i, retval); return (retval < 0) ? retval : -EDOM; @@ -650,14 +633,14 @@ static int ch9_postconfig (struct usbtest_dev *dev) sizeof (struct usb_qualifier_descriptor)); if (retval == -EPIPE) { if (udev->speed == USB_SPEED_HIGH) { - dev_dbg (&iface->dev, + dev_err(&iface->dev, "hs dev qualifier --> %d\n", retval); return (retval < 0) ? retval : -EDOM; } /* usb2.0 but not high-speed capable; fine */ } else if (retval != sizeof (struct usb_qualifier_descriptor)) { - dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval); + dev_err(&iface->dev, "dev qualifier --> %d\n", retval); return (retval < 0) ? retval : -EDOM; } else d = (struct usb_qualifier_descriptor *) dev->buf; @@ -669,8 +652,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) retval = usb_get_descriptor (udev, USB_DT_OTHER_SPEED_CONFIG, i, dev->buf, TBUF_SIZE); - if (!is_good_config (dev->buf, retval)) { - dev_dbg (&iface->dev, + if (!is_good_config(dev, retval)) { + dev_err(&iface->dev, "other speed config --> %d\n", retval); return (retval < 0) ? retval : -EDOM; @@ -683,7 +666,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) /* [9.4.5] get_status always works */ retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf); if (retval != 2) { - dev_dbg (&iface->dev, "get dev status --> %d\n", retval); + dev_err(&iface->dev, "get dev status --> %d\n", retval); return (retval < 0) ? retval : -EDOM; } @@ -693,11 +676,11 @@ static int ch9_postconfig (struct usbtest_dev *dev) retval = usb_get_status (udev, USB_RECIP_INTERFACE, iface->altsetting [0].desc.bInterfaceNumber, dev->buf); if (retval != 2) { - dev_dbg (&iface->dev, "get interface status --> %d\n", retval); + dev_err(&iface->dev, "get interface status --> %d\n", retval); return (retval < 0) ? retval : -EDOM; } // FIXME get status for each endpoint in the interface - + return 0; } @@ -752,8 +735,9 @@ static void ctrl_complete (struct urb *urb) */ if (subcase->number > 0) { if ((subcase->number - ctx->last) != 1) { - dbg ("subcase %d completed out of order, last %d", - subcase->number, ctx->last); + ERROR(ctx->dev, + "subcase %d completed out of order, last %d\n", + subcase->number, ctx->last); status = -EDOM; ctx->last = subcase->number; goto error; @@ -777,7 +761,7 @@ static void ctrl_complete (struct urb *urb) else if (subcase->number == 12 && status == -EPIPE) status = 0; else - dbg ("subtest %d error, status %d", + ERROR(ctx->dev, "subtest %d error, status %d\n", subcase->number, status); } @@ -788,9 +772,12 @@ error: int i; ctx->status = status; - info ("control queue %02x.%02x, err %d, %d left", + ERROR(ctx->dev, "control queue %02x.%02x, err %d, " + "%d left, subcase %d, len %d/%d\n", reqp->bRequestType, reqp->bRequest, - status, ctx->count); + status, ctx->count, subcase->number, + urb->actual_length, + urb->transfer_buffer_length); /* FIXME this "unlink everything" exit route should * be a separate test case. @@ -799,7 +786,8 @@ error: /* unlink whatever's still pending */ for (i = 1; i < ctx->param->sglen; i++) { struct urb *u = ctx->urb [ - (i + subcase->number) % ctx->param->sglen]; + (i + subcase->number) + % ctx->param->sglen]; if (u == urb || !u->dev) continue; @@ -812,7 +800,8 @@ error: case -EIDRM: continue; default: - dbg ("urb unlink --> %d", status); + ERROR(ctx->dev, "urb unlink --> %d\n", + status); } } status = ctx->status; @@ -822,14 +811,15 @@ error: /* resubmit if we need to, else mark this as done */ if ((status == 0) && (ctx->pending < ctx->count)) { if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) { - dbg ("can't resubmit ctrl %02x.%02x, err %d", + ERROR(ctx->dev, + "can't resubmit ctrl %02x.%02x, err %d\n", reqp->bRequestType, reqp->bRequest, status); urb->dev = NULL; } else ctx->pending++; } else urb->dev = NULL; - + /* signal completion when nothing's queued */ if (ctx->pending == 0) complete (&ctx->complete); @@ -918,11 +908,11 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); // interface == 0 len = sizeof (struct usb_interface_descriptor); - expected = EPIPE; + expected = -EPIPE; break; // NOTE: two consecutive stalls in the queue here. // that tests fault recovery a bit more aggressively. - case 8: // clear endpoint halt (USUALLY STALLS) + case 8: // clear endpoint halt (MAY STALL) req.bRequest = USB_REQ_CLEAR_FEATURE; req.bRequestType = USB_RECIP_ENDPOINT; // wValue 0 == ep halt @@ -965,7 +955,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) break; case 14: // short read; try to fill the last packet req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0); - // device descriptor size == 18 bytes + /* device descriptor size == 18 bytes */ len = udev->descriptor.bMaxPacketSize0; switch (len) { case 8: len = 24; break; @@ -974,7 +964,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) expected = -EREMOTEIO; break; default: - err ("bogus number of ctrl queue testcases!"); + ERROR(dev, "bogus number of ctrl queue testcases!\n"); context.status = -EINVAL; goto cleanup; } @@ -1003,7 +993,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) for (i = 0; i < param->sglen; i++) { context.status = usb_submit_urb (urb [i], GFP_ATOMIC); if (context.status != 0) { - dbg ("can't submit urb[%d], status %d", + ERROR(dev, "can't submit urb[%d], status %d\n", i, context.status); context.count = context.pending; break; @@ -1070,7 +1060,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) * due to errors, or is just NAKing requests. */ if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) { - dev_dbg (&dev->intf->dev, "submit fail %d\n", retval); + dev_err(&dev->intf->dev, "submit fail %d\n", retval); return retval; } @@ -1087,13 +1077,13 @@ retry: * "normal" drivers would prevent resubmission, but * since we're testing unlink paths, we can't. */ - dev_dbg (&dev->intf->dev, "unlink retry\n"); + ERROR(dev, "unlink retry\n"); goto retry; } } else usb_kill_urb (urb); if (!(retval == 0 || retval == -EINPROGRESS)) { - dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval); + dev_err(&dev->intf->dev, "unlink fail %d\n", retval); return retval; } @@ -1121,7 +1111,7 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len) /*-------------------------------------------------------------------------*/ -static int verify_not_halted (int ep, struct urb *urb) +static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb) { int retval; u16 status; @@ -1129,20 +1119,21 @@ static int verify_not_halted (int ep, struct urb *urb) /* shouldn't look or act halted */ retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status); if (retval < 0) { - dbg ("ep %02x couldn't get no-halt status, %d", ep, retval); + ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n", + ep, retval); return retval; } if (status != 0) { - dbg ("ep %02x bogus status: %04x != 0", ep, status); + ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status); return -EINVAL; } - retval = simple_io (urb, 1, 0, 0, __func__); + retval = simple_io(tdev, urb, 1, 0, 0, __func__); if (retval != 0) return -EINVAL; return 0; } -static int verify_halted (int ep, struct urb *urb) +static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb) { int retval; u16 status; @@ -1150,29 +1141,30 @@ static int verify_halted (int ep, struct urb *urb) /* should look and act halted */ retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status); if (retval < 0) { - dbg ("ep %02x couldn't get halt status, %d", ep, retval); + ERROR(tdev, "ep %02x couldn't get halt status, %d\n", + ep, retval); return retval; } le16_to_cpus(&status); if (status != 1) { - dbg ("ep %02x bogus status: %04x != 1", ep, status); + ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status); return -EINVAL; } - retval = simple_io (urb, 1, 0, -EPIPE, __func__); + retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__); if (retval != -EPIPE) return -EINVAL; - retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted"); + retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted"); if (retval != -EPIPE) return -EINVAL; return 0; } -static int test_halt (int ep, struct urb *urb) +static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb) { int retval; /* shouldn't look or act halted now */ - retval = verify_not_halted (ep, urb); + retval = verify_not_halted(tdev, ep, urb); if (retval < 0) return retval; @@ -1182,20 +1174,20 @@ static int test_halt (int ep, struct urb *urb) USB_ENDPOINT_HALT, ep, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval < 0) { - dbg ("ep %02x couldn't set halt, %d", ep, retval); + ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval); return retval; } - retval = verify_halted (ep, urb); + retval = verify_halted(tdev, ep, urb); if (retval < 0) return retval; /* clear halt (tests API + protocol), verify it worked */ retval = usb_clear_halt (urb->dev, urb->pipe); if (retval < 0) { - dbg ("ep %02x couldn't clear halt, %d", ep, retval); + ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval); return retval; } - retval = verify_not_halted (ep, urb); + retval = verify_not_halted(tdev, ep, urb); if (retval < 0) return retval; @@ -1217,7 +1209,7 @@ static int halt_simple (struct usbtest_dev *dev) if (dev->in_pipe) { ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN; urb->pipe = dev->in_pipe; - retval = test_halt (ep, urb); + retval = test_halt(dev, ep, urb); if (retval < 0) goto done; } @@ -1225,7 +1217,7 @@ static int halt_simple (struct usbtest_dev *dev) if (dev->out_pipe) { ep = usb_pipeendpoint (dev->out_pipe); urb->pipe = dev->out_pipe; - retval = test_halt (ep, urb); + retval = test_halt(dev, ep, urb); } done: simple_free_urb (urb); @@ -1275,7 +1267,7 @@ static int ctrl_out (struct usbtest_dev *dev, if (retval != len) { what = "write"; if (retval >= 0) { - INFO(dev, "ctrl_out, wlen %d (expected %d)\n", + ERROR(dev, "ctrl_out, wlen %d (expected %d)\n", retval, len); retval = -EBADMSG; } @@ -1289,7 +1281,7 @@ static int ctrl_out (struct usbtest_dev *dev, if (retval != len) { what = "read"; if (retval >= 0) { - INFO(dev, "ctrl_out, rlen %d (expected %d)\n", + ERROR(dev, "ctrl_out, rlen %d (expected %d)\n", retval, len); retval = -EBADMSG; } @@ -1299,7 +1291,7 @@ static int ctrl_out (struct usbtest_dev *dev, /* fail if we can't verify */ for (j = 0; j < len; j++) { if (buf [j] != (u8) (i + j)) { - INFO (dev, "ctrl_out, byte %d is %d not %d\n", + ERROR(dev, "ctrl_out, byte %d is %d not %d\n", j, buf [j], (u8) i + j); retval = -EBADMSG; break; @@ -1321,7 +1313,7 @@ static int ctrl_out (struct usbtest_dev *dev, } if (retval < 0) - INFO (dev, "ctrl_out %s failed, code %d, count %d\n", + ERROR (dev, "ctrl_out %s failed, code %d, count %d\n", what, retval, i); kfree (buf); @@ -1366,7 +1358,7 @@ static void iso_callback (struct urb *urb) case 0: goto done; default: - dev_dbg (&ctx->dev->intf->dev, + dev_err(&ctx->dev->intf->dev, "iso resubmit err %d\n", status); /* FALLTHROUGH */ @@ -1381,7 +1373,7 @@ static void iso_callback (struct urb *urb) ctx->pending--; if (ctx->pending == 0) { if (ctx->errors) - dev_dbg (&ctx->dev->intf->dev, + dev_err(&ctx->dev->intf->dev, "iso test, %lu errors out of %lu\n", ctx->errors, ctx->packet_count); complete (&ctx->done); @@ -1458,7 +1450,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, memset (urbs, 0, sizeof urbs); udev = testdev_to_usbdev (dev); - dev_dbg (&dev->intf->dev, + dev_info(&dev->intf->dev, "... iso period %d %sframes, wMaxPacket %04x\n", 1 << (desc->bInterval - 1), (udev->speed == USB_SPEED_HIGH) ? "micro" : "", @@ -1475,7 +1467,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, urbs [i]->context = &context; } packets *= param->iterations; - dev_dbg (&dev->intf->dev, + dev_info(&dev->intf->dev, "... total %lu msec (%lu packets)\n", (packets * (1 << (desc->bInterval - 1))) / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1), @@ -1537,6 +1529,13 @@ fail: * except indirectly by consuming USB bandwidth and CPU resources for test * threads and request completion. But the only way to know that for sure * is to test when HC queues are in use by many devices. + * + * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(), + * it locks out usbcore in certain code paths. Notably, if you disconnect + * the device-under-test, khubd will wait block forever waiting for the + * ioctl to complete ... so that usb_disconnect() can abort the pending + * urbs and then call usbtest_disconnect(). To abort a test, you're best + * off just killing the userspace task and waiting for it to exit. */ static int @@ -1575,7 +1574,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) * altsettings; force a default so most tests don't need to check. */ if (dev->info->alt >= 0) { - int res; + int res; if (intf->altsetting->desc.bInterfaceNumber) { mutex_unlock(&dev->lock); @@ -1604,7 +1603,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) switch (param->test_num) { case 0: - dev_dbg (&intf->dev, "TEST 0: NOP\n"); + dev_info(&intf->dev, "TEST 0: NOP\n"); retval = 0; break; @@ -1612,7 +1611,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) case 1: if (dev->out_pipe == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 1: write %d bytes %u times\n", param->length, param->iterations); urb = simple_alloc_urb (udev, dev->out_pipe, param->length); @@ -1621,13 +1620,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk sink (maybe accepts short writes) - retval = simple_io (urb, param->iterations, 0, 0, "test1"); + retval = simple_io(dev, urb, param->iterations, 0, 0, "test1"); simple_free_urb (urb); break; case 2: if (dev->in_pipe == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 2: read %d bytes %u times\n", param->length, param->iterations); urb = simple_alloc_urb (udev, dev->in_pipe, param->length); @@ -1636,13 +1635,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk source (maybe generates short writes) - retval = simple_io (urb, param->iterations, 0, 0, "test2"); + retval = simple_io(dev, urb, param->iterations, 0, 0, "test2"); simple_free_urb (urb); break; case 3: if (dev->out_pipe == 0 || param->vary == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 3: write/%d 0..%d bytes %u times\n", param->vary, param->length, param->iterations); urb = simple_alloc_urb (udev, dev->out_pipe, param->length); @@ -1651,14 +1650,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk sink (maybe accepts short writes) - retval = simple_io (urb, param->iterations, param->vary, + retval = simple_io(dev, urb, param->iterations, param->vary, 0, "test3"); simple_free_urb (urb); break; case 4: if (dev->in_pipe == 0 || param->vary == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 4: read/%d 0..%d bytes %u times\n", param->vary, param->length, param->iterations); urb = simple_alloc_urb (udev, dev->in_pipe, param->length); @@ -1667,7 +1666,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk source (maybe generates short writes) - retval = simple_io (urb, param->iterations, param->vary, + retval = simple_io(dev, urb, param->iterations, param->vary, 0, "test4"); simple_free_urb (urb); break; @@ -1676,7 +1675,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) case 5: if (dev->out_pipe == 0 || param->sglen == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 5: write %d sglists %d entries of %d bytes\n", param->iterations, param->sglen, param->length); @@ -1686,7 +1685,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk sink (maybe accepts short writes) - retval = perform_sglist (udev, param->iterations, dev->out_pipe, + retval = perform_sglist(dev, param->iterations, dev->out_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; @@ -1694,7 +1693,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) case 6: if (dev->in_pipe == 0 || param->sglen == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 6: read %d sglists %d entries of %d bytes\n", param->iterations, param->sglen, param->length); @@ -1704,14 +1703,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk source (maybe generates short writes) - retval = perform_sglist (udev, param->iterations, dev->in_pipe, + retval = perform_sglist(dev, param->iterations, dev->in_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; case 7: if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 7: write/%d %d sglists %d entries 0..%d bytes\n", param->vary, param->iterations, param->sglen, param->length); @@ -1721,14 +1720,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk sink (maybe accepts short writes) - retval = perform_sglist (udev, param->iterations, dev->out_pipe, + retval = perform_sglist(dev, param->iterations, dev->out_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; case 8: if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 8: read/%d %d sglists %d entries 0..%d bytes\n", param->vary, param->iterations, param->sglen, param->length); @@ -1738,7 +1737,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) break; } // FIRMWARE: bulk source (maybe generates short writes) - retval = perform_sglist (udev, param->iterations, dev->in_pipe, + retval = perform_sglist(dev, param->iterations, dev->in_pipe, &req, sg, param->sglen); free_sglist (sg, param->sglen); break; @@ -1746,13 +1745,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) /* non-queued sanity tests for control (chapter 9 subset) */ case 9: retval = 0; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 9: ch9 (subset) control tests, %d times\n", param->iterations); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = ch9_postconfig (dev); if (retval) - dbg ("ch9 subset failed, iterations left %d", i); + dev_err(&intf->dev, "ch9 subset failed, " + "iterations left %d\n", i); break; /* queued control messaging */ @@ -1760,7 +1760,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) if (param->sglen == 0) break; retval = 0; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 10: queue %d control calls, %d times\n", param->sglen, param->iterations); @@ -1772,26 +1772,26 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) if (dev->in_pipe == 0 || !param->length) break; retval = 0; - dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n", + dev_info(&intf->dev, "TEST 11: unlink %d reads of %d\n", param->iterations, param->length); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = unlink_simple (dev, dev->in_pipe, param->length); if (retval) - dev_dbg (&intf->dev, "unlink reads failed %d, " + dev_err(&intf->dev, "unlink reads failed %d, " "iterations left %d\n", retval, i); break; case 12: if (dev->out_pipe == 0 || !param->length) break; retval = 0; - dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n", + dev_info(&intf->dev, "TEST 12: unlink %d writes of %d\n", param->iterations, param->length); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = unlink_simple (dev, dev->out_pipe, param->length); if (retval) - dev_dbg (&intf->dev, "unlink writes failed %d, " + dev_err(&intf->dev, "unlink writes failed %d, " "iterations left %d\n", retval, i); break; @@ -1800,24 +1800,24 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) if (dev->out_pipe == 0 && dev->in_pipe == 0) break; retval = 0; - dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n", + dev_info(&intf->dev, "TEST 13: set/clear %d halts\n", param->iterations); for (i = param->iterations; retval == 0 && i--; /* NOP */) retval = halt_simple (dev); - + if (retval) - DBG (dev, "halts failed, iterations left %d\n", i); + ERROR(dev, "halts failed, iterations left %d\n", i); break; /* control write tests */ case 14: if (!dev->info->ctrl_out) break; - dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n", + dev_info(&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n", param->iterations, realworld ? 1 : 0, param->length, param->vary); - retval = ctrl_out (dev, param->iterations, + retval = ctrl_out(dev, param->iterations, param->length, param->vary); break; @@ -1825,7 +1825,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) case 15: if (dev->out_iso_pipe == 0 || param->sglen == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 15: write %d iso, %d entries of %d bytes\n", param->iterations, param->sglen, param->length); @@ -1838,7 +1838,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) case 16: if (dev->in_iso_pipe == 0 || param->sglen == 0) break; - dev_dbg (&intf->dev, + dev_info(&intf->dev, "TEST 16: read %d iso, %d entries of %d bytes\n", param->iterations, param->sglen, param->length); @@ -1898,7 +1898,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product) return -ENODEV; - dbg ("matched module params, vend=0x%04x prod=0x%04x", + dev_info(&intf->dev, "matched module params, " + "vend=0x%04x prod=0x%04x\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); } @@ -1940,7 +1941,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) status = get_endpoints (dev, intf); if (status < 0) { - dbg ("couldn't get endpoints, %d\n", status); + WARN(dev, "couldn't get endpoints, %d\n", + status); return status; } /* may find bulk or ISO pipes */ @@ -2082,21 +2084,9 @@ static struct usbtest_info generic_info = { }; #endif -// FIXME remove this -static struct usbtest_info hact_info = { - .name = "FX2/hact", - //.ep_in = 6, - .ep_out = 2, - .alt = -1, -}; - static struct usb_device_id id_table [] = { - { USB_DEVICE (0x0547, 0x1002), - .driver_info = (unsigned long) &hact_info, - }, - /*-------------------------------------------------------------*/ /* EZ-USB devices which download firmware to replace (or in our @@ -2185,7 +2175,7 @@ static int __init usbtest_init (void) { #ifdef GENERIC if (vendor) - dbg ("params: vend=0x%04x prod=0x%04x", vendor, product); + pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product); #endif return usb_register (&usbtest_driver); } diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index a238817762ad..db6f97a93c02 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -147,7 +147,7 @@ static void serial_buf_free(struct circ_buf *cb) */ static int serial_buf_data_avail(struct circ_buf *cb) { - return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE); + return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE); } /* @@ -171,7 +171,7 @@ static int serial_buf_put(struct circ_buf *cb, const char *buf, int count) cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1); buf += c; count -= c; - ret= c; + ret = c; } return ret; } @@ -197,7 +197,7 @@ static int serial_buf_get(struct circ_buf *cb, char *buf, int count) cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1); buf += c; count -= c; - ret= c; + ret = c; } return ret; } @@ -208,8 +208,8 @@ static void aircable_send(struct usb_serial_port *port) { int count, result; struct aircable_private *priv = usb_get_serial_port_data(port); - unsigned char* buf; - u16 *dbuf; + unsigned char *buf; + __le16 *dbuf; dbg("%s - port %d", __func__, port->number); if (port->write_urb_busy) return; @@ -227,9 +227,10 @@ static void aircable_send(struct usb_serial_port *port) buf[0] = TX_HEADER_0; buf[1] = TX_HEADER_1; - dbuf = (u16 *)&buf[2]; + dbuf = (__le16 *)&buf[2]; *dbuf = cpu_to_le16((u16)count); - serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE); + serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH, + MAX_HCI_FRAMESIZE); memcpy(port->write_urb->transfer_buffer, buf, count + HCI_HEADER_LENGTH); @@ -261,7 +262,7 @@ static void aircable_read(struct work_struct *work) struct tty_struct *tty; unsigned char *data; int count; - if (priv->rx_flags & THROTTLED){ + if (priv->rx_flags & THROTTLED) { if (priv->rx_flags & ACTUALLY_THROTTLED) schedule_work(&priv->rx_work); return; @@ -282,10 +283,10 @@ static void aircable_read(struct work_struct *work) count = min(64, serial_buf_data_avail(priv->rx_buf)); if (count <= 0) - return; //We have finished sending everything. + return; /* We have finished sending everything. */ tty_prepare_flip_string(tty, &data, count); - if (!data){ + if (!data) { err("%s- kzalloc(%d) failed.", __func__, count); return; } @@ -304,9 +305,10 @@ static void aircable_read(struct work_struct *work) static int aircable_probe(struct usb_serial *serial, const struct usb_device_id *id) { - struct usb_host_interface *iface_desc = serial->interface->cur_altsetting; + struct usb_host_interface *iface_desc = serial->interface-> + cur_altsetting; struct usb_endpoint_descriptor *endpoint; - int num_bulk_out=0; + int num_bulk_out = 0; int i; for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { @@ -325,13 +327,13 @@ static int aircable_probe(struct usb_serial *serial, return 0; } -static int aircable_attach (struct usb_serial *serial) +static int aircable_attach(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct aircable_private *priv; priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL); - if (!priv){ + if (!priv) { err("%s- kmalloc(%Zd) failed.", __func__, sizeof(struct aircable_private)); return -ENOMEM; @@ -392,7 +394,7 @@ static int aircable_write(struct usb_serial_port *port, usb_serial_debug_data(debug, &port->dev, __func__, count, source); - if (!count){ + if (!count) { dbg("%s - write request of 0 bytes", __func__); return count; } @@ -418,31 +420,31 @@ static void aircable_write_bulk_callback(struct urb *urb) /* This has been taken from cypress_m8.c cypress_write_int_callback */ switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - port->write_urb_busy = 0; + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __func__, status); + port->write_urb_busy = 0; + return; + default: + /* error in the urb, so we have to resubmit it */ + dbg("%s - Overflow in write", __func__); + dbg("%s - nonzero write bulk status received: %d", + __func__, status); + port->write_urb->transfer_buffer_length = 1; + port->write_urb->dev = port->serial->dev; + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (result) + dev_err(&urb->dev->dev, + "%s - failed resubmitting write urb, error %d\n", + __func__, result); + else return; - default: - /* error in the urb, so we have to resubmit it */ - dbg("%s - Overflow in write", __func__); - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - failed resubmitting write urb, error %d\n", - __func__, result); - else - return; } port->write_urb_busy = 0; @@ -472,11 +474,11 @@ static void aircable_read_bulk_callback(struct urb *urb) dbg("%s - caught -EPROTO, resubmitting the urb", __func__); usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - aircable_read_bulk_callback, port); + usb_rcvbulkpipe(port->serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + aircable_read_bulk_callback, port); result = usb_submit_urb(urb, GFP_ATOMIC); if (result) @@ -490,7 +492,7 @@ static void aircable_read_bulk_callback(struct urb *urb) } usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length,urb->transfer_buffer); + urb->actual_length, urb->transfer_buffer); tty = port->tty; if (tty && urb->actual_length) { @@ -507,9 +509,9 @@ static void aircable_read_bulk_callback(struct urb *urb) no_packages = urb->actual_length / (HCI_COMPLETE_FRAME); if (urb->actual_length % HCI_COMPLETE_FRAME != 0) - no_packages+=1; + no_packages++; - for (i = 0; i < no_packages ;i++) { + for (i = 0; i < no_packages; i++) { if (remaining > (HCI_COMPLETE_FRAME)) package_length = HCI_COMPLETE_FRAME; else @@ -529,7 +531,7 @@ static void aircable_read_bulk_callback(struct urb *urb) if (port->open_count) { usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), + port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, aircable_read_bulk_callback, port); @@ -602,7 +604,7 @@ static struct usb_serial_driver aircable_device = { .unthrottle = aircable_unthrottle, }; -static int __init aircable_init (void) +static int __init aircable_init(void) { int retval; retval = usb_serial_register(&aircable_device); @@ -619,7 +621,7 @@ failed_usb_register: return retval; } -static void __exit aircable_exit (void) +static void __exit aircable_exit(void) { usb_deregister(&aircable_driver); usb_serial_deregister(&aircable_device); diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 725b6b94c274..0798c14ce787 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -68,8 +68,9 @@ static int airprime_send_setup(struct usb_serial_port *port) val |= 0x02; return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + usb_rcvctrlpipe(serial->dev, 0), + 0x22, 0x21, val, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); } return 0; @@ -90,17 +91,19 @@ static void airprime_read_bulk_callback(struct urb *urb) __func__, status); return; } - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __func__, + urb->actual_length, data); tty = port->tty; if (tty && urb->actual_length) { - tty_insert_flip_string (tty, data, urb->actual_length); - tty_flip_buffer_push (tty); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); } - result = usb_submit_urb (urb, GFP_ATOMIC); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", + dev_err(&port->dev, + "%s - failed resubmitting read urb, error %d\n", __func__, result); return; } @@ -115,7 +118,7 @@ static void airprime_write_bulk_callback(struct urb *urb) dbg("%s - port %d", __func__, port->number); /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree (urb->transfer_buffer); + kfree(urb->transfer_buffer); if (status) dbg("%s - nonzero write bulk status received: %d", @@ -171,7 +174,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) } usb_fill_bulk_urb(urb, serial->dev, usb_rcvbulkpipe(serial->dev, - port->bulk_out_endpointAddress), + port->bulk_out_endpointAddress), buffer, buffer_size, airprime_read_bulk_callback, port); result = usb_submit_urb(urb, GFP_KERNEL); @@ -183,7 +186,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) __func__, i, port->number, result); goto errout; } - /* remember this urb so we can kill it when the port is closed */ + /* remember this urb so we can kill it when the + port is closed */ priv->read_urbp[i] = urb; } @@ -192,22 +196,22 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) goto out; errout: - /* some error happened, cancel any submitted urbs and clean up anything that - got allocated successfully */ + /* some error happened, cancel any submitted urbs and clean up + anything that got allocated successfully */ while (i-- != 0) { urb = priv->read_urbp[i]; buffer = urb->transfer_buffer; - usb_kill_urb (urb); - usb_free_urb (urb); - kfree (buffer); + usb_kill_urb(urb); + usb_free_urb(urb); + kfree(buffer); } out: return result; } -static void airprime_close(struct usb_serial_port *port, struct file * filp) +static void airprime_close(struct usb_serial_port *port, struct file *filp) { struct airprime_private *priv = usb_get_serial_port_data(port); int i; @@ -220,16 +224,16 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp) mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) airprime_send_setup(port); - mutex_lock(&port->serial->disc_mutex); + mutex_unlock(&port->serial->disc_mutex); for (i = 0; i < NUM_READ_URBS; ++i) { - usb_kill_urb (priv->read_urbp[i]); - kfree (priv->read_urbp[i]->transfer_buffer); - usb_free_urb (priv->read_urbp[i]); + usb_kill_urb(priv->read_urbp[i]); + kfree(priv->read_urbp[i]->transfer_buffer); + usb_free_urb(priv->read_urbp[i]); } /* free up private structure */ - kfree (priv); + kfree(priv); usb_set_serial_port_data(port, NULL); } @@ -259,10 +263,10 @@ static int airprime_write(struct usb_serial_port *port, urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { dev_err(&port->dev, "no more free urbs\n"); - kfree (buffer); + kfree(buffer); return -ENOMEM; } - memcpy (buffer, buf, count); + memcpy(buffer, buf, count); usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); @@ -279,7 +283,7 @@ static int airprime_write(struct usb_serial_port *port, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status); count = status; - kfree (buffer); + kfree(buffer); } else { spin_lock_irqsave(&priv->lock, flags); ++priv->outstanding_urbs; @@ -287,7 +291,7 @@ static int airprime_write(struct usb_serial_port *port, } /* we are done with this urb, so let the host driver * really free it when it is finished with it */ - usb_free_urb (urb); + usb_free_urb(urb); return count; } @@ -315,8 +319,10 @@ static int __init airprime_init(void) { int retval; - airprime_device.num_ports = - (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS; + airprime_device.num_ports = endpoints; + if (endpoints < 0 || endpoints >= MAX_BULK_EPS) + airprime_device.num_ports = NUM_BULK_EPS; + retval = usb_serial_register(&airprime_device); if (retval) return retval; @@ -341,6 +347,7 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled"); module_param(buffer_size, int, 0); -MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)"); +MODULE_PARM_DESC(buffer_size, + "Size of the transfer buffers in bytes (default 4096)"); module_param(endpoints, int, 0); MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)"); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 599ab2e548a7..77895c8f8f31 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -24,7 +24,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/serial.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> static int debug; @@ -246,29 +246,29 @@ static void ark3116_set_termios(struct usb_serial_port *port, baud = tty_get_baud_rate(port->tty); switch (baud) { - case 75: - case 150: - case 300: - case 600: - case 1200: - case 1800: - case 2400: - case 4800: - case 9600: - case 19200: - case 38400: - case 57600: - case 115200: - case 230400: - case 460800: - /* Report the resulting rate back to the caller */ - tty_encode_baud_rate(port->tty, baud, baud); - break; - /* set 9600 as default (if given baudrate is invalid for example) */ - default: - tty_encode_baud_rate(port->tty, 9600, 9600); - case 0: - baud = 9600; + case 75: + case 150: + case 300: + case 600: + case 1200: + case 1800: + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + case 230400: + case 460800: + /* Report the resulting rate back to the caller */ + tty_encode_baud_rate(port->tty, baud, baud); + break; + /* set 9600 as default (if given baudrate is invalid for example) */ + default: + tty_encode_baud_rate(port->tty, 9600, 9600); + case 0: + baud = 9600; } /* @@ -380,19 +380,19 @@ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file, switch (cmd) { case TIOCGSERIAL: /* XXX: Some of these values are probably wrong. */ - memset(&serstruct, 0, sizeof (serstruct)); + memset(&serstruct, 0, sizeof(serstruct)); serstruct.type = PORT_16654; serstruct.line = port->serial->minor; serstruct.port = port->number; serstruct.custom_divisor = 0; serstruct.baud_base = 460800; - if (copy_to_user(user_arg, &serstruct, sizeof (serstruct))) + if (copy_to_user(user_arg, &serstruct, sizeof(serstruct))) return -EFAULT; return 0; case TIOCSSERIAL: - if (copy_from_user(&serstruct, user_arg, sizeof (serstruct))) + if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) return -EFAULT; return 0; default: diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index d947d955bceb..ba28fdc9ccd2 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -130,7 +130,7 @@ static int ch341_get_status(struct usb_device *dev) return -ENOMEM; r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); - if ( r < 0) + if (r < 0) goto out; /* Not having the datasheet for the CH341, we ignore the bytes returned diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 32121794808d..0230d3c0888a 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -541,7 +541,7 @@ static int cypress_earthmate_startup (struct usb_serial *serial) /* All Earthmate devices use the separated-count packet format! Idiotic. */ priv->pkt_fmt = packet_format_1; - if (serial->dev->descriptor.idProduct != PRODUCT_ID_EARTHMATEUSB) { + if (serial->dev->descriptor.idProduct != cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) { /* The old original USB Earthmate seemed able to handle GET_CONFIG requests; everything they've produced since that time crashes if this command is diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index d17d1645714f..04a56f300ea6 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/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 23f51a41093e..5b349ece7247 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -133,6 +133,14 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, @@ -1104,7 +1112,7 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) struct usb_endpoint_descriptor *ep_desc = &ep->desc; if (ep->enabled && ep_desc->wMaxPacketSize == 0) { - ep_desc->wMaxPacketSize = 0x40; + ep_desc->wMaxPacketSize = cpu_to_le16(0x40); info("Fixing invalid wMaxPacketSize on read pipe"); } diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 6da539ede0ee..504edf8c3a3f 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -40,6 +40,17 @@ /* AlphaMicro Components AMC-232USB01 device */ #define FTDI_AMC232_PID 0xFF00 /* Product Id */ +/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ +/* the VID is the standard ftdi vid (FTDI_VID) */ +#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ +#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */ +#define FTDI_SCS_DEVICE_2_PID 0xD012 +#define FTDI_SCS_DEVICE_3_PID 0xD013 +#define FTDI_SCS_DEVICE_4_PID 0xD014 +#define FTDI_SCS_DEVICE_5_PID 0xD015 +#define FTDI_SCS_DEVICE_6_PID 0xD016 +#define FTDI_SCS_DEVICE_7_PID 0xD017 + /* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */ #define FTDI_ACTZWAVE_PID 0xF2D0 diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index ce2e487f3240..06b52f4098f1 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2993,7 +2993,7 @@ static int edge_startup (struct usb_serial *serial) usb_fill_bulk_urb(edge_serial->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), edge_serial->bulk_in_buffer, - endpoint->wMaxPacketSize, + le16_to_cpu(endpoint->wMaxPacketSize), edge_bulk_in_callback, edge_serial); bulk_in_found = true; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index b395ac759888..f328948d74e3 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -54,6 +54,7 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <asm/uaccess.h> +#include <asm/unaligned.h> #include <linux/usb.h> #include <linux/usb/serial.h> #include "kl5kusb105.h" @@ -235,7 +236,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, if (rc < 0) err("Reading line status failed (error = %d)", rc); else { - status = le16_to_cpu(*(u16 *)status_buf); + status = le16_to_cpu(get_unaligned((__le16 *)status_buf)); info("%s - read status %x %x", __func__, status_buf[0], status_buf[1]); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 6bcb82d3911a..78f2f6db494d 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1713,7 +1713,7 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file, { struct moschip_port *mos7840_port; unsigned int mcr; - unsigned int status; + int status; dbg("%s - port %d", __func__, port->number); @@ -1740,11 +1740,10 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file, mos7840_port->shadowMCR = mcr; - status = 0; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr); if (status < 0) { dbg("setting MODEM_CONTROL_REGISTER Failed\n"); - return -1; + return status; } return 0; diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index d92bb6501c84..a9625c180dc3 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -98,7 +98,7 @@ struct oti6858_buf { /* format of the control packet */ struct oti6858_control_pkt { - u16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */ + __le16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */ #define OTI6858_MAX_BAUD_RATE 3000000 u8 frame_fmt; #define FMT_STOP_BITS_MASK 0xc0 @@ -211,7 +211,7 @@ struct oti6858_private { struct delayed_work delayed_write_work; struct { - u16 divisor; + __le16 divisor; u8 frame_fmt; u8 control; } pending_setup; @@ -450,7 +450,7 @@ static void oti6858_set_termios(struct usb_serial_port *port, unsigned long flags; unsigned int cflag; u8 frame_fmt, control; - u16 divisor; + __le16 divisor; int br; dbg("%s(port = %d)", __func__, port->number); @@ -505,11 +505,12 @@ static void oti6858_set_termios(struct usb_serial_port *port, divisor = 0; } else { int real_br; + int new_divisor; br = min(br, OTI6858_MAX_BAUD_RATE); - divisor = (96000000 + 8 * br) / (16 * br); - real_br = 96000000 / (16 * divisor); - divisor = cpu_to_le16(divisor); + new_divisor = (96000000 + 8 * br) / (16 * br); + real_br = 96000000 / (16 * new_divisor); + divisor = cpu_to_le16(new_divisor); tty_encode_baud_rate(port->tty, real_br, real_br); } diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 2282d620186e..55b2570b8b8b 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -310,17 +310,18 @@ static int spcp8x5_startup(struct usb_serial *serial) struct spcp8x5_private *priv; int i; enum spcp8x5_type type = SPCP825_007_TYPE; + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - if (serial->dev->descriptor.idProduct == 0x0201) + if (product == 0x0201) type = SPCP825_007_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0231) + else if (product == 0x0231) type = SPCP835_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0235) + else if (product == 0x0235) type = SPCP825_008_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0204) + else if (product == 0x0204) type = SPCP825_INTERMATIC_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0471 && - serial->dev->descriptor.idVendor == 0x081e) + else if (product == 0x0471 && + serial->dev->descriptor.idVendor == cpu_to_le16(0x081e)) type = SPCP825_PHILIP_TYPE; dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a9934a3f9845..0cb0d77dc429 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 e96bf8663ffc..f07e8a4c1f3d 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/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 0f6d234d699b..3d9249632ae1 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -123,7 +123,8 @@ config USB_STORAGE_ALAUDA config USB_STORAGE_ONETOUCH bool "Support OneTouch Button on Maxtor Hard Drives" - depends on USB_STORAGE && INPUT_EVDEV + depends on USB_STORAGE + depends on INPUT=y || INPUT=USB_STORAGE help Say Y here to include additional code to support the Maxtor OneTouch USB hard drive's onetouch button. diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c index a28d49122e7a..d617e8ae6b00 100644 --- a/drivers/usb/storage/libusual.c +++ b/drivers/usb/storage/libusual.c @@ -135,7 +135,7 @@ static int usu_probe(struct usb_interface *intf, stat[type].fls |= USU_MOD_FL_THREAD; spin_unlock_irqrestore(&usu_lock, flags); - task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type); + task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type); if (IS_ERR(task)) { rc = PTR_ERR(task); printk(KERN_WARNING "libusual: " diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index dfd42fe9e5f0..98b89ea9e312 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -38,7 +38,7 @@ #include "onetouch.h" #include "debug.h" -void onetouch_release_input(void *onetouch_); +static void onetouch_release_input(void *onetouch_); struct usb_onetouch { char name[128]; @@ -223,7 +223,7 @@ int onetouch_connect_input(struct us_data *ss) return error; } -void onetouch_release_input(void *onetouch_) +static void onetouch_release_input(void *onetouch_) { struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 732bf52a775e..a0ed889230aa 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -44,7 +44,8 @@ * running with this patch. * Send your submission to either Phil Dibowitz <phil@ipom.com> or * Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the - * USB development list <linux-usb-devel@lists.sourceforge.net>. + * USB development list <linux-usb@vger.kernel.org> and the USB storage list + * <usb-storage@lists.one-eyed-alien.net> */ /* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr> @@ -557,6 +558,13 @@ UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999, US_FL_SINGLE_LUN), #endif +/* Reported by Dmitry Khlystov <adminimus@gmail.com> */ +UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220, + "Samsung", + "YP-U3", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64), + /* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, "Belkin", @@ -1200,6 +1208,17 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_BULK32), +/* Andrew Lunn <andrew@lunn.ch> + * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL + * on LUN 4. + * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera" +*/ +UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200, + "PanDigital", + "Photo Frame", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NOT_LOCKABLE), + /* Submitted by Jan De Luyck <lkml@kcore.org> */ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000, "CITIZEN", @@ -1342,6 +1361,13 @@ UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), +/* Reported by Rohan Hart <rohan.hart17@gmail.com> */ +UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010, + "INTOVA", + "Pixtreme", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* * Entry for Jenoptik JD 5200z3 * diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index a856effad3bd..e268aacb773a 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -539,7 +539,8 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id) " has %s in unusual_devs.h (kernel" " %s)\n" " Please send a copy of this message to " - "<linux-usb-devel@lists.sourceforge.net>\n", + "<linux-usb@vger.kernel.org> and " + "<usb-storage@lists.one-eyed-alien.net>\n", le16_to_cpu(ddesc->idVendor), le16_to_cpu(ddesc->idProduct), le16_to_cpu(ddesc->bcdDevice), diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e3dc8f8d0c3e..bb1dadaa4a23 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -139,6 +139,30 @@ config FB_SYS_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version and the framebuffer is in system RAM. +menuconfig FB_FOREIGN_ENDIAN + bool "Framebuffer foreign endianness support" + depends on FB + ---help--- + This menu will let you enable support for the framebuffers with + non-native endianness (e.g. Little-Endian framebuffer on a + Big-Endian machine). Most probably you don't have such hardware, + so it's safe to say "n" here. + +choice + prompt "Choice endianness support" + depends on FB_FOREIGN_ENDIAN + +config FB_BOTH_ENDIAN + bool "Support for Big- and Little-Endian framebuffers" + +config FB_BIG_ENDIAN + bool "Support for Big-Endian framebuffers only" + +config FB_LITTLE_ENDIAN + bool "Support for Little-Endian framebuffers only" + +endchoice + config FB_SYS_FOPS tristate depends on FB @@ -149,6 +173,16 @@ config FB_DEFERRED_IO depends on FB default y +config FB_METRONOME + tristate + depends on FB + depends on FB_DEFERRED_IO + +config FB_HECUBA + tristate + depends on FB + depends on FB_DEFERRED_IO + config FB_SVGALIB tristate depends on FB @@ -546,7 +580,7 @@ config FB_VGA16 config FB_BF54X_LQ043 tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" - depends on FB && (BF54x) + depends on FB && (BF54x) && !BF542 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -674,20 +708,18 @@ config FB_IMAC help This is the frame buffer device driver for the Intel-based Macintosh -config FB_HECUBA - tristate "Hecuba board support" +config FB_N411 + tristate "N411 Apollo/Hecuba devkit support" depends on FB && X86 && MMU select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select FB_HECUBA help - This enables support for the Hecuba board. This driver was tested - with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO - interface (8 bit data, 4 bit control). If you anticipate using - this driver, say Y or M; otherwise say N. You must specify the - GPIO IO address to be used for setting control and data. + This enables support for the Apollo display controller in its + Hecuba form using the n411 devkit. config FB_HGA tristate "Hercules mono graphics support" @@ -1087,7 +1119,7 @@ config FB_CARILLO_RANCH This driver supports the LE80578 (Carillo Ranch) board config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" + tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL @@ -1097,7 +1129,7 @@ config FB_INTEL select FB_CFB_IMAGEBLIT help This driver supports the on-board graphics built in to the Intel - 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets. + 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. Say Y if you have and plan to use such a board. If you say Y here and want DDC/I2C support you must first say Y to @@ -1742,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 @@ -1779,6 +1816,16 @@ config FB_MBX_DEBUG If unsure, say N. +config FB_FSL_DIU + tristate "Freescale DIU framebuffer support" + depends on FB && FSL_SOC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select PPC_LIB_RHEAP + ---help--- + Framebuffer driver for the Freescale SoC DIU + config FB_W100 tristate "W100 frame buffer support" depends on FB && PXA_SHARPSL @@ -1893,19 +1940,18 @@ config FB_XILINX framebuffer. ML300 carries a 640*480 LCD display on the board, ML403 uses a standard DB15 VGA connector. -config FB_METRONOME - tristate "Metronome display controller support" +config FB_AM200EPD + tristate "AM-200 E-Ink EPD devkit support" depends on FB && ARCH_PXA && MMU select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select FB_METRONOME help - This enables support for the Metronome display controller. Tested - with an E-Ink 800x600 display and Gumstix Connex through an AMLCD - interface. Please read <file:Documentation/fb/metronomefb.txt> - for more information. + This enables support for the Metronome display controller used on + the E-Ink AM-200 EPD devkit. config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index f172b9b73314..04bca35403ff 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o # Hardware specific drivers go first obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_AM200EPD) += am200epd.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o @@ -107,6 +108,7 @@ obj-$(CONFIG_FB_METRONOME) += metronomefb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o +obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c new file mode 100644 index 000000000000..51e26c1f5e8b --- /dev/null +++ b/drivers/video/am200epd.c @@ -0,0 +1,295 @@ +/* + * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit + * + * Copyright (C) 2008, Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This work was made possible by help and equipment support from E-Ink + * Corporation. http://support.eink.com/community + * + * This driver is written to be used with the Metronome display controller. + * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600 + * Vizplex EPD on a Gumstix board using the Lyre interface board. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <video/metronomefb.h> + +#include <asm/arch/pxa-regs.h> + +/* register offsets for gpio control */ +#define LED_GPIO_PIN 51 +#define STDBY_GPIO_PIN 48 +#define RST_GPIO_PIN 49 +#define RDY_GPIO_PIN 32 +#define ERR_GPIO_PIN 17 +#define PCBPWR_GPIO_PIN 16 + +#define AF_SEL_GPIO_N 0x3 +#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) +#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) +#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) +#define GPDR1_OFFSET(pin) (pin - 32) +#define GPCR1_OFFSET(pin) (pin - 32) +#define GPSR1_OFFSET(pin) (pin - 32) +#define GPCR0_OFFSET(pin) (pin) +#define GPSR0_OFFSET(pin) (pin) + +static void am200_set_gpio_output(int pin, int val) +{ + u8 index; + + index = pin >> 4; + + switch (index) { + case 1: + if (val) + GPSR0 |= (1 << GPSR0_OFFSET(pin)); + else + GPCR0 |= (1 << GPCR0_OFFSET(pin)); + break; + case 2: + break; + case 3: + if (val) + GPSR1 |= (1 << GPSR1_OFFSET(pin)); + else + GPCR1 |= (1 << GPCR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void __devinit am200_init_gpio_pin(int pin, int dir) +{ + u8 index; + /* dir 0 is output, 1 is input + - do 2 things here: + - set gpio alternate function to standard gpio + - set gpio direction to input or output */ + + index = pin >> 4; + switch (index) { + case 1: + GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); + + if (dir) + GPDR0 &= ~(1 << pin); + else + GPDR0 |= (1 << pin); + break; + case 2: + GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + case 3: + GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void am200_init_gpio_regs(struct metronomefb_par *par) +{ + am200_init_gpio_pin(LED_GPIO_PIN, 0); + am200_set_gpio_output(LED_GPIO_PIN, 0); + + am200_init_gpio_pin(STDBY_GPIO_PIN, 0); + am200_set_gpio_output(STDBY_GPIO_PIN, 0); + + am200_init_gpio_pin(RST_GPIO_PIN, 0); + am200_set_gpio_output(RST_GPIO_PIN, 0); + + am200_init_gpio_pin(RDY_GPIO_PIN, 1); + + am200_init_gpio_pin(ERR_GPIO_PIN, 1); + + am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0); + am200_set_gpio_output(PCBPWR_GPIO_PIN, 0); +} + +static void am200_disable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ + + /* we reset and just wait for things to settle */ + msleep(200); +} + +static void am200_enable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; + FDADR0 = par->metromem_desc_dma; + LCCR0 |= LCCR0_ENB; +} + +static void am200_init_lcdc_regs(struct metronomefb_par *par) +{ + /* here we do: + - disable the lcd controller + - setup lcd control registers + - setup dma descriptor + - reenable lcd controller + */ + + /* disable the lcd controller */ + am200_disable_lcd_controller(par); + + /* setup lcd control registers */ + LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS + | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; + + LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */ + | (27 << 10) /* hsync pulse width - 1 */ + | (33 << 16) /* eol pixel count */ + | (33 << 24); /* bol pixel count */ + + LCCR2 = (par->info->var.yres - 1) /* lines per panel */ + | (24 << 10) /* vsync pulse width - 1 */ + | (2 << 16) /* eof pixel count */ + | (0 << 24); /* bof pixel count */ + + LCCR3 = 2 /* pixel clock divisor */ + | (24 << 8) /* AC Bias pin freq */ + | LCCR3_16BPP /* BPP */ + | LCCR3_PCP; /* PCP falling edge */ + +} + +static void am200_post_dma_setup(struct metronomefb_par *par) +{ + par->metromem_desc->mFDADR0 = par->metromem_desc_dma; + par->metromem_desc->mFSADR0 = par->metromem_dma; + par->metromem_desc->mFIDR0 = 0; + par->metromem_desc->mLDCMD0 = par->info->var.xres + * par->info->var.yres; + am200_enable_lcd_controller(par); +} + +static void am200_free_irq(struct fb_info *info) +{ + free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); +} + +static irqreturn_t am200_handle_irq(int irq, void *dev_id) +{ + struct fb_info *info = dev_id; + struct metronomefb_par *par = info->par; + + wake_up_interruptible(&par->waitq); + return IRQ_HANDLED; +} + +static int am200_setup_irq(struct fb_info *info) +{ + int retval; + + retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq, + IRQF_DISABLED, "AM200", info); + if (retval) { + printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval); + return retval; + } + + return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); +} + +static void am200_set_rst(struct metronomefb_par *par, int state) +{ + am200_set_gpio_output(RST_GPIO_PIN, state); +} + +static void am200_set_stdby(struct metronomefb_par *par, int state) +{ + am200_set_gpio_output(STDBY_GPIO_PIN, state); +} + +static int am200_wait_event(struct metronomefb_par *par) +{ + return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); +} + +static int am200_wait_event_intr(struct metronomefb_par *par) +{ + return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); +} + +static struct metronome_board am200_board = { + .owner = THIS_MODULE, + .free_irq = am200_free_irq, + .setup_irq = am200_setup_irq, + .init_gpio_regs = am200_init_gpio_regs, + .init_lcdc_regs = am200_init_lcdc_regs, + .post_dma_setup = am200_post_dma_setup, + .set_rst = am200_set_rst, + .set_stdby = am200_set_stdby, + .met_wait_event = am200_wait_event, + .met_wait_event_intr = am200_wait_event_intr, +}; + +static struct platform_device *am200_device; + +static int __init am200_init(void) +{ + int ret; + + /* request our platform independent driver */ + request_module("metronomefb"); + + am200_device = platform_device_alloc("metronomefb", -1); + if (!am200_device) + return -ENOMEM; + + platform_device_add_data(am200_device, &am200_board, + sizeof(am200_board)); + + /* this _add binds metronomefb to am200. metronomefb refcounts am200 */ + ret = platform_device_add(am200_device); + + if (ret) + platform_device_put(am200_device); + + return ret; +} + +static void __exit am200_exit(void) +{ + platform_device_unregister(am200_device); +} + +module_init(am200_init); +module_exit(am200_exit); + +MODULE_DESCRIPTION("board driver for am200 metronome epd kit"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 4c9ec3f58c52..e6492c1048bf 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -96,7 +96,7 @@ #endif #ifdef DEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 8a1b07c74394..5001bd4ef466 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -101,7 +101,7 @@ static const struct svga_timing_regs ark_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option __devinitdata = "640x480-8@60"; #ifdef CONFIG_MTRR static int mtrr = 1; @@ -111,8 +111,10 @@ MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for ARK 2000PV"); -module_param(mode, charp, 0444); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0444); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0444); +MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -941,7 +943,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct arkfb_info), NULL); + info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev)); if (! info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -956,20 +958,20 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "arkfb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info); if (! par->dac) { rc = -ENOMEM; - dev_err(&(dev->dev), "RAMDAC initialization failed\n"); + dev_err(info->dev, "RAMDAC initialization failed\n"); goto err_dac; } @@ -980,7 +982,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -999,22 +1001,22 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebugger\n"); + dev_err(info->dev, "cannot register framebugger\n"); goto err_reg_fb; } @@ -1088,7 +1090,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1119,7 +1121,7 @@ static int ark_pci_resume (struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1190,7 +1192,7 @@ static int __init arkfb_init(void) return -ENODEV; if (option && *option) - mode = option; + mode_option = option; #endif pr_debug("arkfb: initializing\n"); diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5d4fbaa53a6c..dff35474b854 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -1270,7 +1270,7 @@ again: gstart = (prescale / 2 + plen * left_margin) / prescale; /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ - gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale; + gend1 = gstart + roundup(xres, align) * plen / prescale; /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ gend2 = gstart + xres * plen / prescale; par->HHT = plen * (left_margin + xres + right_margin) / diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index fc65c02306dd..8ffdf3578768 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -31,7 +31,8 @@ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 #define ATMEL_LCDC_DMA_BURST_LEN 8 -#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) +#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || \ + defined(CONFIG_ARCH_AT91SAM9RL) #define ATMEL_LCDC_FIFO_SIZE 2048 #else #define ATMEL_LCDC_FIFO_SIZE 512 @@ -250,6 +251,8 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) return -ENOMEM; } + memset(info->screen_base, 0, info->fix.smem_len); + return 0; } @@ -336,19 +339,35 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, break; case 15: case 16: - var->red.offset = 0; + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:565 mode */ + var->red.offset = 11; + var->blue.offset = 0; + var->green.length = 6; + } else { + /* BGR:555 mode */ + var->red.offset = 0; + var->blue.offset = 10; + var->green.length = 5; + } var->green.offset = 5; - var->blue.offset = 10; - var->red.length = var->green.length = var->blue.length = 5; + var->red.length = var->blue.length = 5; break; case 32: var->transp.offset = 24; var->transp.length = 8; /* fall through */ case 24: - var->red.offset = 0; + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:888 mode */ + var->red.offset = 16; + var->blue.offset = 0; + } else { + /* BGR:888 mode */ + var->red.offset = 0; + var->blue.offset = 16; + } var->green.offset = 8; - var->blue.offset = 16; var->red.length = var->green.length = var->blue.length = 8; break; default: @@ -634,7 +653,6 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) struct fb_info *info = sinfo->info; int ret = 0; - memset_io(info->screen_base, 0, info->fix.smem_len); info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; dev_info(info->device, @@ -696,6 +714,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; + sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; @@ -764,6 +783,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) goto release_intmem; + + /* + * Don't clear the framebuffer -- someone may have set + * up a splash image. + */ } else { /* alocate memory buffer */ ret = atmel_lcdfb_alloc_video_memory(sinfo); @@ -903,10 +927,42 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM + +static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct atmel_lcdfb_info *sinfo = info->par; + + sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(0); + atmel_lcdfb_stop_clock(sinfo); + return 0; +} + +static int atmel_lcdfb_resume(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct atmel_lcdfb_info *sinfo = info->par; + + atmel_lcdfb_start_clock(sinfo); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(1); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); + return 0; +} + +#else +#define atmel_lcdfb_suspend NULL +#define atmel_lcdfb_resume NULL +#endif + static struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), - -// FIXME need suspend, resume + .suspend = atmel_lcdfb_suspend, + .resume = atmel_lcdfb_resume, .driver = { .name = "atmel_lcdfb", diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index cbd3308b6690..24ee96c4e9e9 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -91,7 +91,7 @@ #undef DEBUG #ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __FUNCTION__, ##args); +#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args); #else #define DBG(fmt, args...) #endif @@ -1885,7 +1885,7 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i /* range check to make sure */ if (ent->driver_data < ARRAY_SIZE(r128_family)) - strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); + strlcat(video_card, r128_family[ent->driver_data], sizeof(video_card)); printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 62f9c6e387cc..e4bcf5376a99 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2621,10 +2621,13 @@ static int __devinit aty_init(struct fb_info *info) #endif /* CONFIG_FB_ATY_CT */ info->var = var; - fb_alloc_cmap(&info->cmap, 256, 0); + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto aty_init_exit; - if (register_framebuffer(info) < 0) + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); goto aty_init_exit; + } fb_list = info; diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c index cc9e9779b75f..c50c7cf26fe9 100644 --- a/drivers/video/aty/mach64_ct.c +++ b/drivers/video/aty/mach64_ct.c @@ -197,7 +197,7 @@ static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks; #ifdef DEBUG printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n", - __FUNCTION__, pll->dsp_config, pll->dsp_on_off); + __func__, pll->dsp_config, pll->dsp_on_off); #endif return 0; } @@ -225,7 +225,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll (par->ref_clk_per * pll->pll_ref_div); #ifdef DEBUG printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n", - __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real); + __func__, pllvclk, pllvclk / pll->vclk_post_div_real); #endif pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ @@ -269,7 +269,7 @@ static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pl } #endif #ifdef DEBUG - printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret); + printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__, ret, ret); #endif return ret; } @@ -284,11 +284,11 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll) #ifdef DEBUG printk("atyfb(%s): about to program:\n" "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n", - __FUNCTION__, + __func__, pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl); printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n", - __FUNCTION__, + __func__, par->clk_wr_offset, pll->ct.vclk_fb_div, pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real); #endif @@ -428,7 +428,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, #ifdef DEBUG printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n", - __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); + __func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); #endif memcntl = aty_ld_le32(MEM_CNTL, par); @@ -540,7 +540,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) / (par->ref_clk_per * pll->ct.pll_ref_div); printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n", - __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); + __func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); #endif if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM)) @@ -581,7 +581,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) / (par->ref_clk_per * pll->ct.pll_ref_div); printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n", - __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real); + __func__, pllsclk, pllsclk / sclk_post_div_real); #endif } diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 62867cb63fef..72cd0d2f14ec 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -52,11 +52,14 @@ #define RADEON_VERSION "0.2.0" +#include "radeonfb.h" + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/ctype.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/delay.h> @@ -91,7 +94,6 @@ #include "../edid.h" // MOVE THAT TO include/video #include "ati_ids.h" -#include "radeonfb.h" #define MAX_MAPPED_VRAM (2048*2048*4) #define MIN_MAPPED_VRAM (1024*768*1) @@ -1488,7 +1490,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs freq = rinfo->pll.ppll_max; if (freq*12 < rinfo->pll.ppll_min) freq = rinfo->pll.ppll_min / 12; - RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n", + pr_debug("freq = %lu, PLL min = %u, PLL max = %u\n", freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { @@ -1509,7 +1511,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } - RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); @@ -1519,7 +1521,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } - RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); @@ -1528,9 +1530,9 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs regs->ppll_ref_div = rinfo->pll.ref_div; regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16); - RTRACE("post div = 0x%x\n", post_div->bitvalue); - RTRACE("fb_div = 0x%x\n", fb_div); - RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3); + pr_debug("post div = 0x%x\n", post_div->bitvalue); + pr_debug("fb_div = 0x%x\n", fb_div); + pr_debug("ppll_div_3 = 0x%x\n", regs->ppll_div_3); } static int radeonfb_set_par(struct fb_info *info) @@ -1602,9 +1604,9 @@ static int radeonfb_set_par(struct fb_info *info) dotClock = 1000000000 / pixClock; freq = dotClock / 10; /* x100 */ - RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", + pr_debug("hStart = %d, hEnd = %d, hTotal = %d\n", hSyncStart, hSyncEnd, hTotal); - RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", + pr_debug("vStart = %d, vEnd = %d, vTotal = %d\n", vSyncStart, vSyncEnd, vTotal); hsync_wid = (hSyncEnd - hSyncStart) / 8; @@ -1713,16 +1715,16 @@ static int radeonfb_set_par(struct fb_info *info) newmode->surf_info[i] = 0; } - RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", + pr_debug("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); - RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", + pr_debug("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); rinfo->bpp = mode->bits_per_pixel; rinfo->depth = depth; - RTRACE("pixclock = %lu\n", (unsigned long)pixClock); - RTRACE("freq = %lu\n", (unsigned long)freq); + pr_debug("pixclock = %lu\n", (unsigned long)pixClock); + pr_debug("freq = %lu\n", (unsigned long)freq); /* We use PPLL_DIV_3 */ newmode->clk_cntl_index = 0x300; @@ -1986,7 +1988,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) if (rinfo->has_CRTC2) OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); - RTRACE("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", + pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", aper_base, ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), 0xffff0000 | (agp_base >> 16)); @@ -2083,7 +2085,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) * ToDo: identify these cases */ - RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", + pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", pci_name(rinfo->pdev), rinfo->video_ram / 1024, rinfo->vram_ddr ? "DDR" : "SDRAM", @@ -2158,8 +2160,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, struct fb_info *info; struct radeonfb_info *rinfo; int ret; + unsigned char c1, c2; - RTRACE("radeonfb_pci_register BEGIN\n"); + pr_debug("radeonfb_pci_register BEGIN\n"); /* Enable device in PCI config */ ret = pci_enable_device(pdev); @@ -2185,9 +2188,15 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, rinfo->lvds_timer.function = radeon_lvds_timer_func; rinfo->lvds_timer.data = (unsigned long)rinfo; - strcpy(rinfo->name, "ATI Radeon XX "); - rinfo->name[11] = ent->device >> 8; - rinfo->name[12] = ent->device & 0xFF; + c1 = ent->device >> 8; + c2 = ent->device & 0xff; + if (isprint(c1) && isprint(c2)) + snprintf(rinfo->name, sizeof(rinfo->name), + "ATI Radeon %x \"%c%c\"", ent->device & 0xffff, c1, c2); + else + snprintf(rinfo->name, sizeof(rinfo->name), + "ATI Radeon %x", ent->device & 0xffff); + rinfo->family = ent->driver_data & CHIP_FAMILY_MASK; rinfo->chipset = pdev->device; rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0; @@ -2278,7 +2287,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, goto err_unmap_rom; } - RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), + pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), rinfo->mapped_vram/1024); /* @@ -2373,7 +2382,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); - RTRACE("radeonfb_pci_register END\n"); + pr_debug("radeonfb_pci_register END\n"); return 0; err_unmap_fb: diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 7db9de681716..f9e7c29ad9bf 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -1,3 +1,5 @@ +#include "radeonfb.h" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -11,7 +13,6 @@ #include <asm/io.h> #include <video/radeon.h> -#include "radeonfb.h" #include "../edid.h" static void radeon_gpio_setscl(void* data, int state) @@ -77,7 +78,7 @@ static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name) chan->algo.setscl = radeon_gpio_setscl; chan->algo.getsda = radeon_gpio_getsda; chan->algo.getscl = radeon_gpio_getscl; - chan->algo.udelay = 40; + chan->algo.udelay = 10; chan->algo.timeout = 20; chan->algo.data = chan; @@ -148,21 +149,21 @@ int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, if (out_edid) *out_edid = edid; if (!edid) { - RTRACE("radeonfb: I2C (port %d) ... not found\n", conn); + pr_debug("radeonfb: I2C (port %d) ... not found\n", conn); return MT_NONE; } if (edid[0x14] & 0x80) { /* Fix detection using BIOS tables */ if (rinfo->is_mobility /*&& conn == ddc_dvi*/ && (INREG(LVDS_GEN_CNTL) & LVDS_ON)) { - RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); return MT_LCD; } else { - RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); return MT_DFP; } } - RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found CRT display\n", conn); return MT_CRT; } diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index 2030ed813429..b4d4b88afc09 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -69,11 +69,11 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ u8 *tmp; int i, mt = MT_NONE; - RTRACE("analyzing OF properties...\n"); + pr_debug("analyzing OF properties...\n"); pmt = of_get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; - RTRACE("display-type: %s\n", pmt); + pr_debug("display-type: %s\n", pmt); /* OF says "LCD" for DFP as well, we discriminate from the caller of this * function */ @@ -117,7 +117,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ { struct device_node *dp; - RTRACE("radeon_probe_OF_head\n"); + pr_debug("radeon_probe_OF_head\n"); dp = rinfo->of_node; while (dp == NULL) @@ -135,7 +135,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ if (!pname) return MT_NONE; len = strlen(pname); - RTRACE("head: %s (letter: %c, head_no: %d)\n", + pr_debug("head: %s (letter: %c, head_no: %d)\n", pname, pname[len-1], head_no); if (pname[len-1] == 'A' && head_no == 0) { int mt = radeon_parse_montype_prop(dp, out_EDID, 0); @@ -185,7 +185,7 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) rinfo->panel_info.xres, rinfo->panel_info.yres); rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44); - RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); + pr_debug("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0) rinfo->panel_info.pwr_delay = 2000; @@ -199,16 +199,16 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) rinfo->panel_info.fbk_divider > 3) { rinfo->panel_info.use_bios_dividers = 1; printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n"); - RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider); - RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider); - RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); + pr_debug("ref_divider = %x\n", rinfo->panel_info.ref_divider); + pr_debug("post_divider = %x\n", rinfo->panel_info.post_divider); + pr_debug("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); } - RTRACE("Scanning BIOS table ...\n"); + pr_debug("Scanning BIOS table ...\n"); for(i=0; i<32; i++) { tmp0 = BIOS_IN16(tmp+64+i*2); if (tmp0 == 0) break; - RTRACE(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); + pr_debug(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) && (BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) { rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8; @@ -227,19 +227,19 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) /* Mark panel infos valid */ rinfo->panel_info.valid = 1; - RTRACE("Found panel in BIOS table:\n"); - RTRACE(" hblank: %d\n", rinfo->panel_info.hblank); - RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); - RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width); - RTRACE(" vblank: %d\n", rinfo->panel_info.vblank); - RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); - RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width); - RTRACE(" clock: %d\n", rinfo->panel_info.clock); + pr_debug("Found panel in BIOS table:\n"); + pr_debug(" hblank: %d\n", rinfo->panel_info.hblank); + pr_debug(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); + pr_debug(" hSync_width: %d\n", rinfo->panel_info.hSync_width); + pr_debug(" vblank: %d\n", rinfo->panel_info.vblank); + pr_debug(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); + pr_debug(" vSync_width: %d\n", rinfo->panel_info.vSync_width); + pr_debug(" clock: %d\n", rinfo->panel_info.clock); return 1; } } - RTRACE("Didn't find panel in BIOS table !\n"); + pr_debug("Didn't find panel in BIOS table !\n"); return 0; } @@ -271,18 +271,18 @@ static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo) * DEBUG is enabled */ chips = BIOS_IN8(offset++) >> 4; - RTRACE("%d chips in connector info\n", chips); + pr_debug("%d chips in connector info\n", chips); for (i = 0; i < chips; i++) { tmp = BIOS_IN8(offset++); connectors = tmp & 0x0f; - RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors); + pr_debug(" - chip %d has %d connectors\n", tmp >> 4, connectors); for (conn = 0; ; conn++) { tmp = BIOS_IN16(offset); if (tmp == 0) break; offset += 2; type = (tmp >> 12) & 0x0f; - RTRACE(" * connector %d of type %d (%s) : %04x\n", + pr_debug(" * connector %d of type %d (%s) : %04x\n", conn, type, __conn_type_table[type], tmp); } } @@ -449,7 +449,7 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * a layout for each card ? */ - RTRACE("Using specified monitor layout: %s", monitor_layout); + pr_debug("Using specified monitor layout: %s", monitor_layout); #ifdef CONFIG_FB_RADEON_I2C if (!ignore_edid) { if (rinfo->mon1_type != MT_NONE) @@ -479,9 +479,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * Auto-detecting display type (well... trying to ...) */ - RTRACE("Starting monitor auto detection...\n"); + pr_debug("Starting monitor auto detection...\n"); -#if DEBUG && defined(CONFIG_FB_RADEON_I2C) +#if defined(DEBUG) && defined(CONFIG_FB_RADEON_I2C) { u8 *EDIDs[4] = { NULL, NULL, NULL, NULL }; int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE}; @@ -756,7 +756,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT && rinfo->mon1_EDID) { struct fb_var_screeninfo var; - RTRACE("Parsing EDID data for panel info\n"); + pr_debug("Parsing EDID data for panel info\n"); if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { if (var.xres >= rinfo->panel_info.xres && var.yres >= rinfo->panel_info.yres) @@ -776,7 +776,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) { struct fb_var_screeninfo *var = &info->var; - RTRACE("Setting up default mode based on panel info\n"); + pr_debug("Setting up default mode based on panel info\n"); var->xres = rinfo->panel_info.xres; var->yres = rinfo->panel_info.yres; var->xres_virtual = rinfo->panel_info.xres; @@ -824,7 +824,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ int dbsize; char modename[32]; - RTRACE("Guessing panel info...\n"); + pr_debug("Guessing panel info...\n"); if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE; rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8; diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 5eac1ce52e72..c347e38cd0b0 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -1,6 +1,10 @@ #ifndef __RADEONFB_H__ #define __RADEONFB_H__ +#ifdef CONFIG_FB_RADEON_DEBUG +#define DEBUG 1 +#endif + #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -365,22 +369,6 @@ struct radeonfb_info { /* - * Debugging stuffs - */ -#ifdef CONFIG_FB_RADEON_DEBUG -#define DEBUG 1 -#else -#define DEBUG 0 -#endif - -#if DEBUG -#define RTRACE printk -#else -#define RTRACE if(0) printk -#endif - - -/* * IO macros */ diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index eefba3d0e4b9..49834a67a623 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -336,7 +336,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, { if (var->bits_per_pixel != LCD_BPP) { - pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, + pr_debug("%s: depth not supported: %u BPP\n", __func__, var->bits_per_pixel); return -EINVAL; } @@ -345,7 +345,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, info->var.xres_virtual != var->xres_virtual || info->var.yres_virtual != var->yres_virtual) { pr_debug("%s: Resolution not supported: X%u x Y%u \n", - __FUNCTION__, var->xres, var->yres); + __func__, var->xres, var->yres); return -EINVAL; } @@ -355,7 +355,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { pr_debug("%s: Memory Limit requested yres_virtual = %u\n", - __FUNCTION__, var->yres_virtual); + __func__, var->yres_virtual); return -ENOMEM; } @@ -652,7 +652,7 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out7; } - if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED, + if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED, "PPI ERROR", info) < 0) { printk(KERN_ERR DRIVER_NAME ": unable to request PPI ERROR IRQ\n"); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 833b10c84064..275d9dab0c61 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -339,7 +339,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: bwtwo at %lx:%lx\n", + printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; @@ -399,10 +399,9 @@ static int __init bw2_init(void) static void __exit bw2_exit(void) { - return of_unregister_driver(&bw2_driver); + of_unregister_driver(&bw2_driver); } - module_init(bw2_init); module_exit(bw2_exit); diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index b07e419b12d2..df03f3776dcc 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -44,15 +44,16 @@ */ static void -bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest @@ -202,8 +203,9 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src */ static void -bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int shift; @@ -221,8 +223,9 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem shift = dst_idx-src_idx; - first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); + first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), + bswapmask); if (!shift) { // Same alignment for source and dest @@ -404,7 +407,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); } } else { @@ -413,7 +416,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 23d70a12e4da..64b35766b2a2 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -36,16 +36,16 @@ */ static void -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits, u32 bswapmask) { unsigned long first, last; if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -93,16 +93,16 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -147,8 +147,9 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, unsigned n, int bits, + u32 bswapmask) { unsigned long val = pat, dat; unsigned long first, last; @@ -156,8 +157,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -217,16 +218,17 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, int right, + unsigned n, int bits) { unsigned long first, last, dat; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -306,7 +308,8 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) p->fbops->fb_sync(p); if (!left) { u32 bswapmask = fb_compute_bswapmask(p); - void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, + void (*fill_op32)(struct fb_info *p, + unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits, u32 bswapmask) = NULL; @@ -325,16 +328,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits, + bswapmask); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long __iomem *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -355,7 +359,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index f598907b42ad..baed57d3cfff 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -38,35 +38,31 @@ #define DEBUG #ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) #else #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -98,7 +94,8 @@ static inline void color_imageblit(const struct fb_image *image, val = 0; if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -108,20 +105,21 @@ static inline void color_imageblit(const struct fb_image *image, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -152,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * u32 bswapmask = fb_compute_bswapmask(p); dst2 = (u32 __iomem *) dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -164,7 +162,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write leading bits */ if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -172,13 +171,13 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -187,7 +186,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write trailing bits */ if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -223,13 +223,13 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * u32 __iomem *dst; const u32 *tab = NULL; int i, j, k; - + switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index fdc9f43ec30a..0db0fecba93b 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -556,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: cgfourteen at %lx:%lx, %dMB\n", + printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, par->iospace, par->physbase, par->ramsize >> 20); @@ -605,7 +605,7 @@ static struct of_platform_driver cg14_driver = { .remove = __devexit_p(cg14_remove), }; -int __init cg14_init(void) +static int __init cg14_init(void) { if (fb_get_options("cg14fb", NULL)) return -ENODEV; @@ -613,7 +613,7 @@ int __init cg14_init(void) return of_register_driver(&cg14_driver, &of_bus_type); } -void __exit cg14_exit(void) +static void __exit cg14_exit(void) { of_unregister_driver(&cg14_driver); } diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index a5c7fb331527..010ea53978f8 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -419,7 +419,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: cg3 at %lx:%lx\n", + printk(KERN_INFO "%s: cg3 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 549891d76ef5..fc90db6da65a 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -781,7 +781,7 @@ static int __devinit cg6_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: CGsix [%s] at %lx:%lx\n", + printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, par->which_io, par->physbase); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index f7e2d5add831..35ac9d956b3d 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -81,7 +81,7 @@ /* debug output */ #ifdef CIRRUSFB_DEBUG #define DPRINTK(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) + printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -91,7 +91,7 @@ #define assert(expr) \ if (!(expr)) { \ printk("Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __FUNCTION__, __LINE__); \ + #expr, __FILE__, __func__, __LINE__); \ } #else #define assert(expr) @@ -3117,7 +3117,7 @@ static void bestclock(long freq, long *best, long *nom, } } } - d = ((143181 * n) + f - 1) / f; + d = DIV_ROUND_UP(143181 * n, f); if ((d >= 7) && (d <= 63)) { if (d > 31) d = (d / 2) * 2; diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 17b5267f44d7..9f8a389dc7ae 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -381,7 +381,7 @@ int __init clps711xfb_init(void) /* Register the /proc entries. */ clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, - &proc_root); + NULL); if (clps7111fb_backlight_proc_entry == NULL) { printk("Couldn't create the /proc entry for the backlight.\n"); return -EINVAL; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 022282494d3f..ad31983b43eb 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -92,7 +92,7 @@ #include "fbcon.h" #ifdef FBCONDEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif @@ -620,8 +620,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, if (fb_get_color_depth(&info->var, &info->fix) == 1) erase &= ~0x400; logo_height = fb_prepare_logo(info, ops->rotate); - logo_lines = (logo_height + vc->vc_font.height - 1) / - vc->vc_font.height; + logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * rows); step = logo_lines * cols; @@ -1882,7 +1881,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; break; @@ -1954,7 +1953,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; } @@ -1973,7 +1972,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; break; @@ -2043,7 +2042,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; } diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 3706307e70ed..0135e0395456 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -104,10 +104,14 @@ struct fbcon_ops { #define attr_blink(s) \ ((s) & 0x8000) -#define mono_col(info) \ - (~(0xfff << (max((info)->var.green.length, \ - max((info)->var.red.length, \ - (info)->var.blue.length)))) & 0xff) + +static inline int mono_col(const struct fb_info *info) +{ + __u32 max_len; + max_len = max(info->var.green.length, info->var.red.length); + max_len = max(info->var.blue.length, max_len); + return ~(0xfff << (max_len & 0xff)); +} static inline int attr_col_ec(int shift, struct vc_data *vc, struct fb_info *info, int is_fg) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index bd8d995fe25d..38a296bbdfc9 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -531,7 +531,7 @@ static void mdacon_cursor(struct vc_data *c, int mode) static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { - u16 eattr = mda_convert_attr(c->vc_video_erase_char); + u16 eattr = mda_convert_attr(c->vc_scrl_erase_char); if (!lines) return 0; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 67a682d6cc7b..a11cc2fdd4cd 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) switch (dir) { case SM_UP: sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols); - sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char); + sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); break; case SM_DOWN: sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols); - sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char); + sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); break; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 6df29a62d720..bd1f57b259d9 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1350,7 +1350,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin += delta; scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - - delta), c->vc_video_erase_char, + delta), c->vc_scrl_erase_char, delta); } else { if (oldo - delta < vga_vram_base) { @@ -1363,7 +1363,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, + scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char, delta); } c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index a2a0618d86a5..1db622192bde 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -94,41 +94,44 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) +static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index, + u32 bswapmask) { u32 mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~(u32)0, index); + mask = FB_SHIFT_HIGH(p, ~(u32)0, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < 32) #endif - mask |= FB_SHIFT_HIGH(~(u32)0, + mask |= FB_SHIFT_HIGH(p, ~(u32)0, (index + bswapmask) & ~(bswapmask)); } return mask; } -static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask) +static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p, + u32 index, + u32 bswapmask) { unsigned long mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~0UL, index); + mask = FB_SHIFT_HIGH(p, ~0UL, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < BITS_PER_LONG) #endif - mask |= FB_SHIFT_HIGH(~0UL, + mask |= FB_SHIFT_HIGH(p, ~0UL, (index + bswapmask) & ~(bswapmask)); } return mask; @@ -158,8 +161,8 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) -#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) +#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i)) +#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i)) #define fb_compute_bswapmask(...) 0 #endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 01072f4b3e8f..776f7fcd2fbf 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -26,6 +26,7 @@ #include <linux/init.h> #include <linux/linux_logo.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/console.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -632,27 +633,51 @@ int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } int fb_show_logo(struct fb_info *info, int rotate) { return 0; } #endif /* CONFIG_LOGO */ -static int fbmem_read_proc(char *buf, char **start, off_t offset, - int len, int *eof, void *private) +static void *fb_seq_start(struct seq_file *m, loff_t *pos) { - struct fb_info **fi; - int clen; - - clen = 0; - for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && clen < 4000; - fi++) - if (*fi) - clen += sprintf(buf + clen, "%d %s\n", - (*fi)->node, - (*fi)->fix.id); - *start = buf + offset; - if (clen > offset) - clen -= offset; - else - clen = 0; - return clen < len ? clen : len; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void fb_seq_stop(struct seq_file *m, void *v) +{ +} + +static int fb_seq_show(struct seq_file *m, void *v) +{ + int i = *(loff_t *)v; + struct fb_info *fi = registered_fb[i]; + + if (fi) + seq_printf(m, "%d %s\n", fi->node, fi->fix.id); + return 0; +} + +static const struct seq_operations proc_fb_seq_ops = { + .start = fb_seq_start, + .next = fb_seq_next, + .stop = fb_seq_stop, + .show = fb_seq_show, +}; + +static int proc_fb_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &proc_fb_seq_ops); } +static const struct file_operations fb_proc_fops = { + .owner = THIS_MODULE, + .open = proc_fb_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -1057,7 +1082,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case FBIOPUT_CON2FBMAP: if (copy_from_user(&con2fb, argp, sizeof(con2fb))) return - EFAULT; - if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) return -EINVAL; @@ -1352,6 +1377,32 @@ static const struct file_operations fb_fops = { struct class *fb_class; EXPORT_SYMBOL(fb_class); + +static int fb_check_foreignness(struct fb_info *fi) +{ + const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; + + fi->flags &= ~FBINFO_FOREIGN_ENDIAN; + +#ifdef __BIG_ENDIAN + fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; +#else + fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; +#endif /* __BIG_ENDIAN */ + + if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } + + return 0; +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1371,6 +1422,10 @@ register_framebuffer(struct fb_info *fb_info) if (num_registered_fb == FB_MAX) return -ENXIO; + + if (fb_check_foreignness(fb_info)) + return -ENOSYS; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1503,7 +1558,7 @@ void fb_set_suspend(struct fb_info *info, int state) static int __init fbmem_init(void) { - create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); + proc_create("fb", 0, NULL, &fb_proc_fops); if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index d7e24889650e..93dca3e2aa50 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -32,7 +32,6 @@ static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int ffb_blank(int, struct fb_info *); -static void ffb_init_fix(struct fb_info *); static void ffb_imageblit(struct fb_info *, const struct fb_image *); static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *); @@ -1001,7 +1000,7 @@ static int __devinit ffb_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: %s at %016lx, type %d, " + printk(KERN_INFO "%s: %s at %016lx, type %d, " "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", dp->full_name, ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), @@ -1062,7 +1061,7 @@ static struct of_platform_driver ffb_driver = { .remove = __devexit_p(ffb_remove), }; -int __init ffb_init(void) +static int __init ffb_init(void) { if (fb_get_options("ffb", NULL)) return -ENODEV; @@ -1070,7 +1069,7 @@ int __init ffb_init(void) return of_register_driver(&ffb_driver, &of_bus_type); } -void __exit ffb_exit(void) +static void __exit ffb_exit(void) { of_unregister_driver(&ffb_driver); } diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c new file mode 100644 index 000000000000..b50bb03cb5ab --- /dev/null +++ b/drivers/video/fsl-diu-fb.c @@ -0,0 +1,1721 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale DIU Frame Buffer device driver + * + * Authors: Hongjun Chen <hong-jun.chen@freescale.com> + * Paul Widmer <paul.widmer@freescale.com> + * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> + +#include <linux/of_platform.h> + +#include <sysdev/fsl_soc.h> +#include "fsl-diu-fb.h" + +/* + * These parameters give default parameters + * for video output 1024x768, + * FIXME - change timing to proper amounts + * hsync 31.5kHz, vsync 60Hz + */ +static struct fb_videomode __devinitdata fsl_diu_default_mode = { + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15385, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + +static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { + { + .name = "1024x768-60", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15385, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1024x768-70", + .refresh = 70, + .xres = 1024, + .yres = 768, + .pixclock = 16886, + .left_margin = 3, + .right_margin = 3, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 40, + .vsync_len = 18, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1024x768-75", + .refresh = 75, + .xres = 1024, + .yres = 768, + .pixclock = 15009, + .left_margin = 3, + .right_margin = 3, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 80, + .vsync_len = 32, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-60", + .refresh = 60, + .xres = 1280, + .yres = 1024, + .pixclock = 9375, + .left_margin = 38, + .right_margin = 128, + .upper_margin = 2, + .lower_margin = 7, + .hsync_len = 216, + .vsync_len = 37, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-70", + .refresh = 70, + .xres = 1280, + .yres = 1024, + .pixclock = 9380, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 4, + .lower_margin = 4, + .hsync_len = 60, + .vsync_len = 94, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-75", + .refresh = 75, + .xres = 1280, + .yres = 1024, + .pixclock = 9380, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 4, + .lower_margin = 4, + .hsync_len = 60, + .vsync_len = 15, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "320x240", /* for AOI only */ + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = 15385, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x480-60", + .refresh = 60, + .xres = 1280, + .yres = 480, + .pixclock = 18939, + .left_margin = 353, + .right_margin = 47, + .upper_margin = 39, + .lower_margin = 4, + .hsync_len = 8, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, +}; + +static char *fb_mode = "1024x768-32@60"; +static unsigned long default_bpp = 32; +static int monitor_port; + +#if defined(CONFIG_NOT_COHERENT_CACHE) +static u8 *coherence_data; +static size_t coherence_data_size; +static unsigned int d_cache_line_size; +#endif + +static DEFINE_SPINLOCK(diu_lock); + +struct fsl_diu_data { + struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; + /*FSL_AOI_NUM has one dummy AOI */ + struct device_attribute dev_attr; + struct diu_ad *dummy_ad; + void *dummy_aoi_virt; + unsigned int irq; + int fb_enabled; + int monitor_port; +}; + +struct mfb_info { + int index; + int type; + char *id; + int registered; + int blank; + unsigned long pseudo_palette[16]; + struct diu_ad *ad; + int cursor_reset; + unsigned char g_alpha; + unsigned int count; + int x_aoi_d; /* aoi display x offset to physical screen */ + int y_aoi_d; /* aoi display y offset to physical screen */ + struct fsl_diu_data *parent; +}; + + +static struct mfb_info mfb_template[] = { + { /* AOI 0 for plane 0 */ + .index = 0, + .type = MFB_TYPE_OUTPUT, + .id = "Panel0", + .registered = 0, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 0, + }, + { /* AOI 0 for plane 1 */ + .index = 1, + .type = MFB_TYPE_OUTPUT, + .id = "Panel1 AOI0", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 0, + }, + { /* AOI 1 for plane 1 */ + .index = 2, + .type = MFB_TYPE_OUTPUT, + .id = "Panel1 AOI1", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 480, + }, + { /* AOI 0 for plane 2 */ + .index = 3, + .type = MFB_TYPE_OUTPUT, + .id = "Panel2 AOI0", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 640, + .y_aoi_d = 0, + }, + { /* AOI 1 for plane 2 */ + .index = 4, + .type = MFB_TYPE_OUTPUT, + .id = "Panel2 AOI1", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 640, + .y_aoi_d = 480, + }, +}; + +static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), +}; + +static struct diu_pool pool; + +/* To allocate memory for framebuffer. First try __get_free_pages(). If it + * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate + * very large memory (more than 4MB). We don't want to allocate all memory + * in rheap since small memory allocation/deallocation will fragment the + * rheap and make the furture large allocation fail. + */ + +void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys) +{ + void *virt; + + pr_debug("size=%lu\n", size); + + virt = (void *)__get_free_pages(GFP_DMA | __GFP_ZERO, get_order(size)); + if (virt) { + *phys = virt_to_phys(virt); + pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); + return virt; + } + if (!diu_ops.diu_mem) { + printk(KERN_INFO "%s: no diu_mem." + " To reserve more memory, put 'diufb=15M' " + "in the command line\n", __func__); + return NULL; + } + + virt = (void *)rh_alloc(&diu_ops.diu_rh_info, size, "DIU"); + if (virt) { + *phys = virt_to_bus(virt); + memset(virt, 0, size); + } + + pr_debug("rh virt=%p phys=%lx\n", virt, *phys); + + return virt; +} + +void fsl_diu_free(void *p, unsigned long size) +{ + pr_debug("p=%p size=%lu\n", p, size); + + if (!p) + return; + + if ((p >= diu_ops.diu_mem) && + (p < (diu_ops.diu_mem + diu_ops.diu_size))) { + pr_debug("rh\n"); + rh_free(&diu_ops.diu_rh_info, (unsigned long) p); + } else { + pr_debug("dma\n"); + free_pages((unsigned long)p, get_order(size)); + } +} + +static int fsl_diu_enable_panel(struct fb_info *info) +{ + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct diu *hw = dr.diu_reg; + struct diu_ad *ad = mfbi->ad; + struct fsl_diu_data *machine_data = mfbi->parent; + int res = 0; + + pr_debug("enable_panel index %d\n", mfbi->index); + if (mfbi->type != MFB_TYPE_OFF) { + switch (mfbi->index) { + case 0: /* plane 0 */ + if (hw->desc[0] != ad->paddr) + out_be32(&hw->desc[0], ad->paddr); + break; + case 1: /* plane 1 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[2]->par; + if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ + if (cmfbi->count > 0) /* AOI1 open */ + ad->next_ad = + cpu_to_le32(cmfbi->ad->paddr); + else + ad->next_ad = 0; + out_be32(&hw->desc[1], ad->paddr); + } + break; + case 3: /* plane 2 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[4]->par; + if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ + if (cmfbi->count > 0) /* AOI1 open */ + ad->next_ad = + cpu_to_le32(cmfbi->ad->paddr); + else + ad->next_ad = 0; + out_be32(&hw->desc[2], ad->paddr); + } + break; + case 2: /* plane 1 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[1]->par; + ad->next_ad = 0; + if (hw->desc[1] == machine_data->dummy_ad->paddr) + out_be32(&hw->desc[1], ad->paddr); + else /* AOI0 open */ + pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); + break; + case 4: /* plane 2 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[3]->par; + ad->next_ad = 0; + if (hw->desc[2] == machine_data->dummy_ad->paddr) + out_be32(&hw->desc[2], ad->paddr); + else /* AOI0 was open */ + pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); + break; + default: + res = -EINVAL; + break; + } + } else + res = -EINVAL; + return res; +} + +static int fsl_diu_disable_panel(struct fb_info *info) +{ + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct diu *hw = dr.diu_reg; + struct diu_ad *ad = mfbi->ad; + struct fsl_diu_data *machine_data = mfbi->parent; + int res = 0; + + switch (mfbi->index) { + case 0: /* plane 0 */ + if (hw->desc[0] != machine_data->dummy_ad->paddr) + out_be32(&hw->desc[0], + machine_data->dummy_ad->paddr); + break; + case 1: /* plane 1 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[2]->par; + if (cmfbi->count > 0) /* AOI1 is open */ + out_be32(&hw->desc[1], cmfbi->ad->paddr); + /* move AOI1 to the first */ + else /* AOI1 was closed */ + out_be32(&hw->desc[1], + machine_data->dummy_ad->paddr); + /* close AOI 0 */ + break; + case 3: /* plane 2 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[4]->par; + if (cmfbi->count > 0) /* AOI1 is open */ + out_be32(&hw->desc[2], cmfbi->ad->paddr); + /* move AOI1 to the first */ + else /* AOI1 was closed */ + out_be32(&hw->desc[2], + machine_data->dummy_ad->paddr); + /* close AOI 0 */ + break; + case 2: /* plane 1 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[1]->par; + if (hw->desc[1] != ad->paddr) { + /* AOI1 is not the first in the chain */ + if (pmfbi->count > 0) + /* AOI0 is open, must be the first */ + pmfbi->ad->next_ad = 0; + } else /* AOI1 is the first in the chain */ + out_be32(&hw->desc[1], machine_data->dummy_ad->paddr); + /* close AOI 1 */ + break; + case 4: /* plane 2 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[3]->par; + if (hw->desc[2] != ad->paddr) { + /* AOI1 is not the first in the chain */ + if (pmfbi->count > 0) + /* AOI0 is open, must be the first */ + pmfbi->ad->next_ad = 0; + } else /* AOI1 is the first in the chain */ + out_be32(&hw->desc[2], machine_data->dummy_ad->paddr); + /* close AOI 1 */ + break; + default: + res = -EINVAL; + break; + } + + return res; +} + +static void enable_lcdc(struct fb_info *info) +{ + struct diu *hw = dr.diu_reg; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + + if (!machine_data->fb_enabled) { + out_be32(&hw->diu_mode, dr.mode); + machine_data->fb_enabled++; + } +} + +static void disable_lcdc(struct fb_info *info) +{ + struct diu *hw = dr.diu_reg; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + + if (machine_data->fb_enabled) { + out_be32(&hw->diu_mode, 0); + machine_data->fb_enabled = 0; + } +} + +static void adjust_aoi_size_position(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + int available_height, upper_aoi_bottom, index = mfbi->index; + int lower_aoi_is_open, upper_aoi_is_open; + __u32 base_plane_width, base_plane_height, upper_aoi_height; + + base_plane_width = machine_data->fsl_diu_info[0]->var.xres; + base_plane_height = machine_data->fsl_diu_info[0]->var.yres; + + switch (index) { + case 0: + if (mfbi->x_aoi_d != 0) + mfbi->x_aoi_d = 0; + if (mfbi->y_aoi_d != 0) + mfbi->y_aoi_d = 0; + break; + case 1: /* AOI 0 */ + case 3: + lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; + lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; + if (var->xres > base_plane_width) + var->xres = base_plane_width; + if ((mfbi->x_aoi_d + var->xres) > base_plane_width) + mfbi->x_aoi_d = base_plane_width - var->xres; + + if (lower_aoi_is_open) + available_height = lower_aoi_mfbi->y_aoi_d; + else + available_height = base_plane_height; + if (var->yres > available_height) + var->yres = available_height; + if ((mfbi->y_aoi_d + var->yres) > available_height) + mfbi->y_aoi_d = available_height - var->yres; + break; + case 2: /* AOI 1 */ + case 4: + upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; + upper_aoi_height = + machine_data->fsl_diu_info[index-1]->var.yres; + upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; + upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; + if (var->xres > base_plane_width) + var->xres = base_plane_width; + if ((mfbi->x_aoi_d + var->xres) > base_plane_width) + mfbi->x_aoi_d = base_plane_width - var->xres; + if (mfbi->y_aoi_d < 0) + mfbi->y_aoi_d = 0; + if (upper_aoi_is_open) { + if (mfbi->y_aoi_d < upper_aoi_bottom) + mfbi->y_aoi_d = upper_aoi_bottom; + available_height = base_plane_height + - upper_aoi_bottom; + } else + available_height = base_plane_height; + if (var->yres > available_height) + var->yres = available_height; + if ((mfbi->y_aoi_d + var->yres) > base_plane_height) + mfbi->y_aoi_d = base_plane_height - var->yres; + break; + } +} +/* + * Checks to see if the hardware supports the state requested by var passed + * in. This function does not alter the hardware state! If the var passed in + * is slightly off by what the hardware can support then we alter the var + * PASSED in to what we can do. If the hardware doesn't support mode change + * a -EINVAL will be returned by the upper layers. + */ +static int fsl_diu_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned long htotal, vtotal; + + pr_debug("check_var xres: %d\n", var->xres); + pr_debug("check_var yres: %d\n", var->yres); + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xoffset < 0) + var->xoffset = 0; + + if (var->yoffset < 0) + var->yoffset = 0; + + if (var->xoffset + info->var.xres > info->var.xres_virtual) + var->xoffset = info->var.xres_virtual - info->var.xres; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + var->yoffset = info->var.yres_virtual - info->var.yres; + + if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && + (var->bits_per_pixel != 16)) + var->bits_per_pixel = default_bpp; + + switch (var->bits_per_pixel) { + case 16: + var->red.length = 5; + var->red.offset = 11; + var->red.msb_right = 0; + + var->green.length = 6; + var->green.offset = 5; + var->green.msb_right = 0; + + var->blue.length = 5; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 24: + var->red.length = 8; + var->red.offset = 0; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 16; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 32: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 8; + var->transp.offset = 24; + var->transp.msb_right = 0; + + break; + } + /* If the pixclock is below the minimum spec'd value then set to + * refresh rate for 60Hz since this is supported by most monitors. + * Refer to Documentation/fb/ for calculations. + */ + if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) { + htotal = var->xres + var->right_margin + var->hsync_len + + var->left_margin; + vtotal = var->yres + var->lower_margin + var->vsync_len + + var->upper_margin; + var->pixclock = (vtotal * htotal * 6UL) / 100UL; + var->pixclock = KHZ2PICOS(var->pixclock); + pr_debug("pixclock set for 60Hz refresh = %u ps\n", + var->pixclock); + } + + var->height = -1; + var->width = -1; + var->grayscale = 0; + + /* Copy nonstd field to/from sync for fbset usage */ + var->sync |= var->nonstd; + var->nonstd |= var->sync; + + adjust_aoi_size_position(var, info); + return 0; +} + +static void set_fix(struct fb_info *info) +{ + struct fb_fix_screeninfo *fix = &info->fix; + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + + strncpy(fix->id, mfbi->id, strlen(mfbi->id)); + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; +} + +static void update_lcdc(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu *hw; + int i, j; + char __iomem *cursor_base, *gamma_table_base; + + u32 temp; + + hw = dr.diu_reg; + + if (mfbi->type == MFB_TYPE_OFF) { + fsl_diu_disable_panel(info); + return; + } + + diu_ops.set_monitor_port(machine_data->monitor_port); + gamma_table_base = pool.gamma.vaddr; + cursor_base = pool.cursor.vaddr; + /* Prep for DIU init - gamma table, cursor table */ + + for (i = 0; i <= 2; i++) + for (j = 0; j <= 255; j++) + *gamma_table_base++ = j; + + diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr); + + pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw); + disable_lcdc(info); + + /* Program DIU registers */ + + out_be32(&hw->gamma, pool.gamma.paddr); + out_be32(&hw->cursor, pool.cursor.paddr); + + out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ + out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ + out_be32(&hw->disp_size, (var->yres << 16 | var->xres)); + /* DISP SIZE */ + pr_debug("DIU xres: %d\n", var->xres); + pr_debug("DIU yres: %d\n", var->yres); + + out_be32(&hw->wb_size, 0); /* WB SIZE */ + out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ + + /* Horizontal and vertical configuration register */ + temp = var->left_margin << 22 | /* BP_H */ + var->hsync_len << 11 | /* PW_H */ + var->right_margin; /* FP_H */ + + out_be32(&hw->hsyn_para, temp); + + temp = var->upper_margin << 22 | /* BP_V */ + var->vsync_len << 11 | /* PW_V */ + var->lower_margin; /* FP_V */ + + out_be32(&hw->vsyn_para, temp); + + pr_debug("DIU right_margin - %d\n", var->right_margin); + pr_debug("DIU left_margin - %d\n", var->left_margin); + pr_debug("DIU hsync_len - %d\n", var->hsync_len); + pr_debug("DIU upper_margin - %d\n", var->upper_margin); + pr_debug("DIU lower_margin - %d\n", var->lower_margin); + pr_debug("DIU vsync_len - %d\n", var->vsync_len); + pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para); + pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para); + + diu_ops.set_pixel_clock(var->pixclock); + + out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ + out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ + out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ + out_be32(&hw->plut, 0x01F5F666); + + /* Enable the DIU */ + enable_lcdc(info); +} + +static int map_video_memory(struct fb_info *info) +{ + phys_addr_t phys; + + pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); + pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); + pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + + info->fix.smem_len = info->fix.line_length * info->var.yres_virtual; + pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); + info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); + if (info->screen_base == 0) { + printk(KERN_ERR "Unable to allocate fb memory\n"); + return -ENOMEM; + } + info->fix.smem_start = (unsigned long) phys; + info->screen_size = info->fix.smem_len; + + pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", + info->fix.smem_start, + info->fix.smem_len); + pr_debug("screen base %p\n", info->screen_base); + + return 0; +} + +static void unmap_video_memory(struct fb_info *info) +{ + fsl_diu_free(info->screen_base, info->fix.smem_len); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; +} + +/* + * Using the fb_var_screeninfo in fb_info we set the resolution of this + * particular framebuffer. This function alters the fb_fix_screeninfo stored + * in fb_info. It does not alter var in fb_info since we are using that + * data. This means we depend on the data in var inside fb_info to be + * supported by the hardware. fsl_diu_check_var is always called before + * fsl_diu_set_par to ensure this. + */ +static int fsl_diu_set_par(struct fb_info *info) +{ + unsigned long len; + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu_ad *ad = mfbi->ad; + struct diu *hw; + + hw = dr.diu_reg; + + set_fix(info); + mfbi->cursor_reset = 1; + + len = info->var.yres_virtual * info->fix.line_length; + /* Alloc & dealloc each time resolution/bpp change */ + if (len != info->fix.smem_len) { + if (info->fix.smem_start) + unmap_video_memory(info); + pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len); + + /* Memory allocation for framebuffer */ + if (map_video_memory(info)) { + printk(KERN_ERR "Unable to allocate fb memory 1\n"); + return -ENOMEM; + } + } + + ad->pix_fmt = + diu_ops.get_pixel_format(var->bits_per_pixel, + machine_data->monitor_port); + ad->addr = cpu_to_le32(info->fix.smem_start); + ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) | + var->xres) | mfbi->g_alpha; + /* fix me. AOI should not be greater than display size */ + ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); + ad->offset_xyi = 0; + ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); + + /* Disable chroma keying function */ + ad->ckmax_r = 0; + ad->ckmax_g = 0; + ad->ckmax_b = 0; + + ad->ckmin_r = 255; + ad->ckmin_g = 255; + ad->ckmin_b = 255; + + if (mfbi->index == 0) + update_lcdc(info); + return 0; +} + +static inline __u32 CNVT_TOHW(__u32 val, __u32 width) +{ + return ((val<<width) + 0x7FFF - val)>>16; +} + +/* + * Set a single color register. The values supplied have a 16 bit magnitude + * which needs to be scaled in this function for the hardware. Things to take + * into consideration are how many color registers, if any, are supported with + * the current color visual. With truecolor mode no color palettes are + * supported. Here a psuedo palette is created which we store the value in + * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited + * color palette. + */ +static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + int ret = 1; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + u32 v; + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + pal[regno] = v; + ret = 0; + } + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + + return ret; +} + +/* + * Pan (or wrap, depending on the `vmode' field) the display using the + * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values + * don't fit, return -EINVAL. + */ +static int fsl_diu_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if ((info->var.xoffset == var->xoffset) && + (info->var.yoffset == var->yoffset)) + return 0; /* No change, do nothing */ + + if (var->xoffset < 0 || var->yoffset < 0 + || var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + + return 0; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking + * succeeded, != 0 if un-/blanking failed. + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int fsl_diu_blank(int blank_mode, struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + mfbi->blank = blank_mode; + + switch (blank_mode) { + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + /* FIXME: fixes to enable_panel and enable lcdc needed */ + case FB_BLANK_NORMAL: + /* fsl_diu_disable_panel(info);*/ + break; + case FB_BLANK_POWERDOWN: + /* disable_lcdc(info); */ + break; + case FB_BLANK_UNBLANK: + /* fsl_diu_enable_panel(info);*/ + break; + } + + return 0; +} + +static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct mfb_info *mfbi = info->par; + struct diu_ad *ad = mfbi->ad; + struct mfb_chroma_key ck; + unsigned char global_alpha; + struct aoi_display_offset aoi_d; + __u32 pix_fmt; + void __user *buf = (void __user *)arg; + + if (!arg) + return -EINVAL; + switch (cmd) { + case MFB_SET_PIXFMT: + if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) + return -EFAULT; + ad->pix_fmt = pix_fmt; + pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); + break; + case MFB_GET_PIXFMT: + pix_fmt = ad->pix_fmt; + if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) + return -EFAULT; + pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); + break; + case MFB_SET_AOID: + if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) + return -EFAULT; + mfbi->x_aoi_d = aoi_d.x_aoi_d; + mfbi->y_aoi_d = aoi_d.y_aoi_d; + pr_debug("set AOI display offset of index %d to (%d,%d)\n", + mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); + fsl_diu_check_var(&info->var, info); + fsl_diu_set_par(info); + break; + case MFB_GET_AOID: + aoi_d.x_aoi_d = mfbi->x_aoi_d; + aoi_d.y_aoi_d = mfbi->y_aoi_d; + if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) + return -EFAULT; + pr_debug("get AOI display offset of index %d (%d,%d)\n", + mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); + break; + case MFB_GET_ALPHA: + global_alpha = mfbi->g_alpha; + if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) + return -EFAULT; + pr_debug("get global alpha of index %d\n", mfbi->index); + break; + case MFB_SET_ALPHA: + /* set panel information */ + if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) + return -EFAULT; + ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | + (global_alpha & 0xff); + mfbi->g_alpha = global_alpha; + pr_debug("set global alpha for index %d\n", mfbi->index); + break; + case MFB_SET_CHROMA_KEY: + /* set panel winformation */ + if (copy_from_user(&ck, buf, sizeof(ck))) + return -EFAULT; + + if (ck.enable && + (ck.red_max < ck.red_min || + ck.green_max < ck.green_min || + ck.blue_max < ck.blue_min)) + return -EINVAL; + + if (!ck.enable) { + ad->ckmax_r = 0; + ad->ckmax_g = 0; + ad->ckmax_b = 0; + ad->ckmin_r = 255; + ad->ckmin_g = 255; + ad->ckmin_b = 255; + } else { + ad->ckmax_r = ck.red_max; + ad->ckmax_g = ck.green_max; + ad->ckmax_b = ck.blue_max; + ad->ckmin_r = ck.red_min; + ad->ckmin_g = ck.green_min; + ad->ckmin_b = ck.blue_min; + } + pr_debug("set chroma key\n"); + break; + case FBIOGET_GWINFO: + if (mfbi->type == MFB_TYPE_OFF) + return -ENODEV; + /* get graphic window information */ + if (copy_to_user(buf, ad, sizeof(*ad))) + return -EFAULT; + break; + case FBIOGET_HWCINFO: + pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); + break; + case FBIOPUT_MODEINFO: + pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); + break; + case FBIOGET_DISPINFO: + pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); + break; + + default: + printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); + return -ENOIOCTLCMD; + } + + return 0; +} + +/* turn on fb if count == 1 + */ +static int fsl_diu_open(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int res = 0; + + spin_lock(&diu_lock); + mfbi->count++; + if (mfbi->count == 1) { + pr_debug("open plane index %d\n", mfbi->index); + fsl_diu_check_var(&info->var, info); + res = fsl_diu_set_par(info); + if (res < 0) + mfbi->count--; + else { + res = fsl_diu_enable_panel(info); + if (res < 0) + mfbi->count--; + } + } + + spin_unlock(&diu_lock); + return res; +} + +/* turn off fb if count == 0 + */ +static int fsl_diu_release(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int res = 0; + + spin_lock(&diu_lock); + mfbi->count--; + if (mfbi->count == 0) { + pr_debug("release plane index %d\n", mfbi->index); + res = fsl_diu_disable_panel(info); + if (res < 0) + mfbi->count++; + } + spin_unlock(&diu_lock); + return res; +} + +static struct fb_ops fsl_diu_ops = { + .owner = THIS_MODULE, + .fb_check_var = fsl_diu_check_var, + .fb_set_par = fsl_diu_set_par, + .fb_setcolreg = fsl_diu_setcolreg, + .fb_blank = fsl_diu_blank, + .fb_pan_display = fsl_diu_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_ioctl = fsl_diu_ioctl, + .fb_open = fsl_diu_open, + .fb_release = fsl_diu_release, +}; + +static int init_fbinfo(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + info->device = NULL; + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_diu_ops; + info->flags = FBINFO_FLAG_DEFAULT; + info->pseudo_palette = &mfbi->pseudo_palette; + + /* Allocate colormap */ + fb_alloc_cmap(&info->cmap, 16, 0); + return 0; +} + +static int install_fb(struct fb_info *info) +{ + int rc; + struct mfb_info *mfbi = info->par; + const char *aoi_mode, *init_aoi_mode = "320x240"; + + if (init_fbinfo(info)) + return -EINVAL; + + if (mfbi->index == 0) /* plane 0 */ + aoi_mode = fb_mode; + else + aoi_mode = init_aoi_mode; + pr_debug("mode used = %s\n", aoi_mode); + rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, + ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); + + switch (rc) { + case 1: + pr_debug("using mode specified in @mode\n"); + break; + case 2: + pr_debug("using mode specified in @mode " + "with ignored refresh rate\n"); + break; + case 3: + pr_debug("using mode default mode\n"); + break; + case 4: + pr_debug("using mode from list\n"); + break; + default: + pr_debug("rc = %d\n", rc); + pr_debug("failed to find mode\n"); + return -EINVAL; + break; + } + + pr_debug("xres_virtual %d\n", info->var.xres_virtual); + pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); + + pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); + pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + + if (mfbi->type == MFB_TYPE_OFF) + mfbi->blank = FB_BLANK_NORMAL; + else + mfbi->blank = FB_BLANK_UNBLANK; + + if (fsl_diu_check_var(&info->var, info)) { + printk(KERN_ERR "fb_check_var failed"); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + if (fsl_diu_set_par(info)) { + printk(KERN_ERR "fb_set_par failed"); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR "register_framebuffer failed"); + unmap_video_memory(info); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + mfbi->registered = 1; + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", + info->node, info->fix.id); + + return 0; +} + +static void __exit uninstall_fb(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + if (!mfbi->registered) + return; + + unregister_framebuffer(info); + unmap_video_memory(info); + if (&info->cmap) + fb_dealloc_cmap(&info->cmap); + + mfbi->registered = 0; +} + +static irqreturn_t fsl_diu_isr(int irq, void *dev_id) +{ + struct diu *hw = dr.diu_reg; + unsigned int status = in_be32(&hw->int_status); + + if (status) { + /* This is the workaround for underrun */ + if (status & INT_UNDRUN) { + out_be32(&hw->diu_mode, 0); + pr_debug("Err: DIU occurs underrun!\n"); + udelay(1); + out_be32(&hw->diu_mode, 1); + } +#if defined(CONFIG_NOT_COHERENT_CACHE) + else if (status & INT_VSYNC) { + unsigned int i; + for (i = 0; i < coherence_data_size; + i += d_cache_line_size) + __asm__ __volatile__ ( + "dcbz 0, %[input]" + ::[input]"r"(&coherence_data[i])); + } +#endif + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int request_irq_local(int irq) +{ + unsigned long status, ints; + struct diu *hw; + int ret; + + hw = dr.diu_reg; + + /* Read to clear the status */ + status = in_be32(&hw->int_status); + + ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0); + if (ret) + pr_info("Request diu IRQ failed.\n"); + else { + ints = INT_PARERR | INT_LS_BF_VS; +#if !defined(CONFIG_NOT_COHERENT_CACHE) + ints |= INT_VSYNC; +#endif + if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) + ints |= INT_VSYNC_WB; + + /* Read to clear the status */ + status = in_be32(&hw->int_status); + out_be32(&hw->int_mask, ints); + } + return ret; +} + +static void free_irq_local(int irq) +{ + struct diu *hw = dr.diu_reg; + + /* Disable all LCDC interrupt */ + out_be32(&hw->int_mask, 0x1f); + + free_irq(irq, 0); +} + +#ifdef CONFIG_PM +/* + * Power management hooks. Note that we won't be called from IRQ context, + * unlike the blank functions above, so we may sleep. + */ +static int fsl_diu_suspend(struct of_device *dev, pm_message_t state) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +} + +static int fsl_diu_resume(struct of_device *dev) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + enable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +} + +#else +#define fsl_diu_suspend NULL +#define fsl_diu_resume NULL +#endif /* CONFIG_PM */ + +/* Align to 64-bit(8-byte), 32-byte, etc. */ +static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + u32 offset, ssize; + u32 mask; + dma_addr_t paddr = 0; + + ssize = size + bytes_align; + buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO); + if (!buf->vaddr) + return -ENOMEM; + + buf->paddr = (__u32) paddr; + + mask = bytes_align - 1; + offset = (u32)buf->paddr & mask; + if (offset) { + buf->offset = bytes_align - offset; + buf->paddr = (u32)buf->paddr + offset; + } else + buf->offset = 0; + return 0; +} + +static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + dma_free_coherent(0, size + bytes_align, + buf->vaddr, (buf->paddr - buf->offset)); + return; +} + +static ssize_t store_monitor(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int old_monitor_port; + unsigned long val; + struct fsl_diu_data *machine_data = + container_of(attr, struct fsl_diu_data, dev_attr); + + if (strict_strtoul(buf, 10, &val)) + return 0; + + old_monitor_port = machine_data->monitor_port; + machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); + + if (old_monitor_port != machine_data->monitor_port) { + /* All AOIs need adjust pixel format + * fsl_diu_set_par only change the pixsel format here + * unlikely to fail. */ + fsl_diu_set_par(machine_data->fsl_diu_info[0]); + fsl_diu_set_par(machine_data->fsl_diu_info[1]); + fsl_diu_set_par(machine_data->fsl_diu_info[2]); + fsl_diu_set_par(machine_data->fsl_diu_info[3]); + fsl_diu_set_par(machine_data->fsl_diu_info[4]); + } + return count; +} + +static ssize_t show_monitor(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fsl_diu_data *machine_data = + container_of(attr, struct fsl_diu_data, dev_attr); + return diu_ops.show_monitor_port(machine_data->monitor_port, buf); +} + +static int fsl_diu_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct mfb_info *mfbi; + phys_addr_t dummy_ad_addr; + int ret, i, error = 0; + struct resource res; + struct fsl_diu_data *machine_data; + + machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); + if (!machine_data) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { + machine_data->fsl_diu_info[i] = + framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); + if (!machine_data->fsl_diu_info[i]) { + dev_err(&ofdev->dev, "cannot allocate memory\n"); + ret = -ENOMEM; + goto error2; + } + mfbi = machine_data->fsl_diu_info[i]->par; + memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); + mfbi->parent = machine_data; + } + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(&ofdev->dev, "could not obtain DIU address\n"); + goto error; + } + if (!res.start) { + dev_err(&ofdev->dev, "invalid DIU address\n"); + goto error; + } + dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); + + dr.diu_reg = ioremap(res.start, sizeof(struct diu)); + if (!dr.diu_reg) { + dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); + ret = -EFAULT; + goto error2; + } + + out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ + + /* Get the IRQ of the DIU */ + machine_data->irq = irq_of_parse_and_map(np, 0); + + if (!machine_data->irq) { + dev_err(&ofdev->dev, "could not get DIU IRQ\n"); + ret = -EINVAL; + goto error; + } + machine_data->monitor_port = monitor_port; + + /* Area descriptor memory pool aligns to 64-bit boundary */ + if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) + return -ENOMEM; + + /* Get memory for Gamma Table - 32-byte aligned memory */ + if (allocate_buf(&pool.gamma, 768, 32)) { + ret = -ENOMEM; + goto error; + } + + /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ + if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) { + ret = -ENOMEM; + goto error; + } + + i = ARRAY_SIZE(machine_data->fsl_diu_info); + machine_data->dummy_ad = (struct diu_ad *) + ((u32)pool.ad.vaddr + pool.ad.offset) + i; + machine_data->dummy_ad->paddr = pool.ad.paddr + + i * sizeof(struct diu_ad); + machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); + if (!machine_data->dummy_aoi_virt) { + ret = -ENOMEM; + goto error; + } + machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); + machine_data->dummy_ad->pix_fmt = 0x88882317; + machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); + machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); + machine_data->dummy_ad->offset_xyi = 0; + machine_data->dummy_ad->offset_xyd = 0; + machine_data->dummy_ad->next_ad = 0; + + out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); + + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { + machine_data->fsl_diu_info[i]->fix.smem_start = 0; + mfbi = machine_data->fsl_diu_info[i]->par; + mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr + + pool.ad.offset) + i; + mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); + ret = install_fb(machine_data->fsl_diu_info[i]); + if (ret) { + dev_err(&ofdev->dev, + "Failed to register framebuffer %d\n", + i); + goto error; + } + } + + if (request_irq_local(machine_data->irq)) { + dev_err(machine_data->fsl_diu_info[0]->dev, + "could not request irq for diu."); + goto error; + } + + machine_data->dev_attr.attr.name = "monitor"; + machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; + machine_data->dev_attr.show = show_monitor; + machine_data->dev_attr.store = store_monitor; + error = device_create_file(machine_data->fsl_diu_info[0]->dev, + &machine_data->dev_attr); + if (error) { + dev_err(machine_data->fsl_diu_info[0]->dev, + "could not create sysfs %s file\n", + machine_data->dev_attr.attr.name); + } + + dev_set_drvdata(&ofdev->dev, machine_data); + return 0; + +error: + for (i = ARRAY_SIZE(machine_data->fsl_diu_info); + i > 0; i--) + uninstall_fb(machine_data->fsl_diu_info[i - 1]); + if (pool.ad.vaddr) + free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + if (pool.gamma.vaddr) + free_buf(&pool.gamma, 768, 32); + if (pool.cursor.vaddr) + free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + if (machine_data->dummy_aoi_virt) + fsl_diu_free(machine_data->dummy_aoi_virt, 64); + iounmap(dr.diu_reg); + +error2: + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) + if (machine_data->fsl_diu_info[i]) + framebuffer_release(machine_data->fsl_diu_info[i]); + kfree(machine_data); + + return ret; +} + + +static int fsl_diu_remove(struct of_device *ofdev) +{ + struct fsl_diu_data *machine_data; + int i; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + free_irq_local(machine_data->irq); + for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) + uninstall_fb(machine_data->fsl_diu_info[i - 1]); + if (pool.ad.vaddr) + free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + if (pool.gamma.vaddr) + free_buf(&pool.gamma, 768, 32); + if (pool.cursor.vaddr) + free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + if (machine_data->dummy_aoi_virt) + fsl_diu_free(machine_data->dummy_aoi_virt, 64); + iounmap(dr.diu_reg); + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) + if (machine_data->fsl_diu_info[i]) + framebuffer_release(machine_data->fsl_diu_info[i]); + kfree(machine_data); + + return 0; +} + +#ifndef MODULE +static int __init fsl_diu_setup(char *options) +{ + char *opt; + unsigned long val; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "monitor=", 8)) { + if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) + monitor_port = val; + } else if (!strncmp(opt, "bpp=", 4)) { + if (!strict_strtoul(opt + 4, 10, &val)) + default_bpp = val; + } else + fb_mode = opt; + } + + return 0; +} +#endif + +static struct of_device_id fsl_diu_match[] = { + { + .compatible = "fsl,diu", + }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_diu_match); + +static struct of_platform_driver fsl_diu_driver = { + .owner = THIS_MODULE, + .name = "fsl_diu", + .match_table = fsl_diu_match, + .probe = fsl_diu_probe, + .remove = fsl_diu_remove, + .suspend = fsl_diu_suspend, + .resume = fsl_diu_resume, +}; + +static int __init fsl_diu_init(void) +{ +#ifdef CONFIG_NOT_COHERENT_CACHE + struct device_node *np; + const u32 *prop; +#endif + int ret; +#ifndef MODULE + char *option; + + /* + * For kernel boot options (in 'video=xxxfb:<options>' format) + */ + if (fb_get_options("fslfb", &option)) + return -ENODEV; + fsl_diu_setup(option); +#endif + printk(KERN_INFO "Freescale DIU driver\n"); + +#ifdef CONFIG_NOT_COHERENT_CACHE + np = of_find_node_by_type(NULL, "cpu"); + if (!np) { + printk(KERN_ERR "Err: can't find device node 'cpu'\n"); + return -ENODEV; + } + + prop = of_get_property(np, "d-cache-size", NULL); + if (prop == NULL) + return -ENODEV; + + /* Freescale PLRU requires 13/8 times the cache size to do a proper + displacement flush + */ + coherence_data_size = *prop * 13; + coherence_data_size /= 8; + + prop = of_get_property(np, "d-cache-line-size", NULL); + if (prop == NULL) + return -ENODEV; + d_cache_line_size = *prop; + + of_node_put(np); + coherence_data = vmalloc(coherence_data_size); + if (!coherence_data) + return -ENOMEM; +#endif + ret = of_register_platform_driver(&fsl_diu_driver); + if (ret) { + printk(KERN_ERR + "fsl-diu: failed to register platform driver\n"); +#if defined(CONFIG_NOT_COHERENT_CACHE) + vfree(coherence_data); +#endif + iounmap(dr.diu_reg); + } + return ret; +} + +static void __exit fsl_diu_exit(void) +{ + of_unregister_platform_driver(&fsl_diu_driver); +#if defined(CONFIG_NOT_COHERENT_CACHE) + vfree(coherence_data); +#endif +} + +module_init(fsl_diu_init); +module_exit(fsl_diu_exit); + +MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); +MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); +MODULE_LICENSE("GPL"); + +module_param_named(mode, fb_mode, charp, 0); +MODULE_PARM_DESC(mode, + "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +module_param_named(bpp, default_bpp, ulong, 0); +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); +module_param_named(monitor, monitor_port, int, 0); +MODULE_PARM_DESC(monitor, + "Specify the monitor port (0, 1 or 2) if supported by the platform"); + diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h new file mode 100644 index 000000000000..fc295d7ea463 --- /dev/null +++ b/drivers/video/fsl-diu-fb.h @@ -0,0 +1,223 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale DIU Frame Buffer device driver + * + * Authors: Hongjun Chen <hong-jun.chen@freescale.com> + * Paul Widmer <paul.widmer@freescale.com> + * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __FSL_DIU_FB_H__ +#define __FSL_DIU_FB_H__ + +/* Arbitrary threshold to determine the allocation method + * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory() + */ +#define MEM_ALLOC_THRESHOLD (1024*768*4+32) +/* Minimum value that the pixel clock can be set to in pico seconds + * This is determined by platform clock/3 where the minimum platform + * clock is 533MHz. This gives 5629 pico seconds. + */ +#define MIN_PIX_CLK 5629 +#define MAX_PIX_CLK 96096 + +#include <linux/types.h> + +struct mfb_alpha { + int enable; + int alpha; +}; + +struct mfb_chroma_key { + int enable; + __u8 red_max; + __u8 green_max; + __u8 blue_max; + __u8 red_min; + __u8 green_min; + __u8 blue_min; +}; + +struct aoi_display_offset { + int x_aoi_d; + int y_aoi_d; +}; + +#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key) +#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t) +#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8) + +#define MFB_SET_ALPHA 0x80014d00 +#define MFB_GET_ALPHA 0x40014d00 +#define MFB_SET_AOID 0x80084d04 +#define MFB_GET_AOID 0x40084d04 +#define MFB_SET_PIXFMT 0x80014d08 +#define MFB_GET_PIXFMT 0x40014d08 + +#define FBIOGET_GWINFO 0x46E0 +#define FBIOPUT_GWINFO 0x46E1 + +#ifdef __KERNEL__ +#include <linux/spinlock.h> + +/* + * These are the fields of area descriptor(in DDR memory) for every plane + */ +struct diu_ad { + /* Word 0(32-bit) in DDR memory */ +/* __u16 comp; */ +/* __u16 pixel_s:2; */ +/* __u16 pallete:1; */ +/* __u16 red_c:2; */ +/* __u16 green_c:2; */ +/* __u16 blue_c:2; */ +/* __u16 alpha_c:3; */ +/* __u16 byte_f:1; */ +/* __u16 res0:3; */ + + __be32 pix_fmt; /* hard coding pixel format */ + + /* Word 1(32-bit) in DDR memory */ + __le32 addr; + + /* Word 2(32-bit) in DDR memory */ +/* __u32 delta_xs:11; */ +/* __u32 res1:1; */ +/* __u32 delta_ys:11; */ +/* __u32 res2:1; */ +/* __u32 g_alpha:8; */ + __le32 src_size_g_alpha; + + /* Word 3(32-bit) in DDR memory */ +/* __u32 delta_xi:11; */ +/* __u32 res3:5; */ +/* __u32 delta_yi:11; */ +/* __u32 res4:3; */ +/* __u32 flip:2; */ + __le32 aoi_size; + + /* Word 4(32-bit) in DDR memory */ + /*__u32 offset_xi:11; + __u32 res5:5; + __u32 offset_yi:11; + __u32 res6:5; + */ + __le32 offset_xyi; + + /* Word 5(32-bit) in DDR memory */ + /*__u32 offset_xd:11; + __u32 res7:5; + __u32 offset_yd:11; + __u32 res8:5; */ + __le32 offset_xyd; + + + /* Word 6(32-bit) in DDR memory */ + __u8 ckmax_r; + __u8 ckmax_g; + __u8 ckmax_b; + __u8 res9; + + /* Word 7(32-bit) in DDR memory */ + __u8 ckmin_r; + __u8 ckmin_g; + __u8 ckmin_b; + __u8 res10; +/* __u32 res10:8; */ + + /* Word 8(32-bit) in DDR memory */ + __le32 next_ad; + + /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */ + __u32 paddr; +} __attribute__ ((packed)); + +/* DIU register map */ +struct diu { + __be32 desc[3]; + __be32 gamma; + __be32 pallete; + __be32 cursor; + __be32 curs_pos; + __be32 diu_mode; + __be32 bgnd; + __be32 bgnd_wb; + __be32 disp_size; + __be32 wb_size; + __be32 wb_mem_addr; + __be32 hsyn_para; + __be32 vsyn_para; + __be32 syn_pol; + __be32 thresholds; + __be32 int_status; + __be32 int_mask; + __be32 colorbar[8]; + __be32 filling; + __be32 plut; +} __attribute__ ((packed)); + +struct diu_hw { + struct diu *diu_reg; + spinlock_t reg_lock; + + __u32 mode; /* DIU operation mode */ +}; + +struct diu_addr { + __u8 __iomem *vaddr; /* Virtual address */ + dma_addr_t paddr; /* Physical address */ + __u32 offset; +}; + +struct diu_pool { + struct diu_addr ad; + struct diu_addr gamma; + struct diu_addr pallete; + struct diu_addr cursor; +}; + +#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */ +#define INT_LCDC 64 /* DIU interrupt number */ + +#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ + /* 1 for plane 0, 2 for plane 1&2 each */ + +/* Minimum X and Y resolutions */ +#define MIN_XRES 64 +#define MIN_YRES 64 + +/* HW cursor parameters */ +#define MAX_CURS 32 + +/* Modes of operation of DIU */ +#define MFB_MODE0 0 /* DIU off */ +#define MFB_MODE1 1 /* All three planes output to display */ +#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/ +#define MFB_MODE3 3 /* All three planes written back to memory */ +#define MFB_MODE4 4 /* Color bar generation */ + +/* INT_STATUS/INT_MASK field descriptions */ +#define INT_VSYNC 0x01 /* Vsync interrupt */ +#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */ +#define INT_UNDRUN 0x04 /* Under run exception interrupt */ +#define INT_PARERR 0x08 /* Display parameters error interrupt */ +#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ + +/* Panels'operation modes */ +#define MFB_TYPE_OUTPUT 0 /* Panel output to display */ +#define MFB_TYPE_OFF 1 /* Panel off */ +#define MFB_TYPE_WB 2 /* Panel written back to memory */ +#define MFB_TYPE_TEST 3 /* Panel generate color bar */ + +#endif /* __KERNEL__ */ +#endif /* __FSL_DIU_FB_H__ */ diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig index 7608429b3943..c5d8ba4b9fc3 100644 --- a/drivers/video/geode/Kconfig +++ b/drivers/video/geode/Kconfig @@ -38,26 +38,6 @@ config FB_GEODE_GX If unsure, say N. -config FB_GEODE_GX_SET_FBSIZE - bool "Manually specify the Geode GX framebuffer size" - depends on FB_GEODE_GX - default n - ---help--- - If you want to manually specify the size of your GX framebuffer, - say Y here, otherwise say N to dynamically probe it. - - Say N unless you know what you are doing. - -config FB_GEODE_GX_FBSIZE - hex "Size of the GX framebuffer, in bytes" - depends on FB_GEODE_GX_SET_FBSIZE - default "0x1600000" - ---help--- - Specify the size of the GX framebuffer. Normally, you will - want this to be MB aligned. Common values are 0x80000 (8MB) - and 0x1600000 (16MB). Don't change this unless you know what - you are doing - config FB_GEODE_GX1 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" depends on FB && FB_GEODE && EXPERIMENTAL diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile index 957304b45fba..5c98da126883 100644 --- a/drivers/video/geode/Makefile +++ b/drivers/video/geode/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o obj-$(CONFIG_FB_GEODE_LX) += lxfb.o gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o -gxfb-objs := gxfb_core.o display_gx.o video_gx.o +gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o lxfb-objs := lxfb_core.o lxfb_ops.o diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c index 0f16e4bffc6c..e759895bf3d3 100644 --- a/drivers/video/geode/display_gx.c +++ b/drivers/video/geode/display_gx.c @@ -17,31 +17,40 @@ #include <asm/io.h> #include <asm/div64.h> #include <asm/delay.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "display_gx.h" +#include "gxfb.h" -#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE -unsigned int gx_frame_buffer_size(void) -{ - return CONFIG_FB_GEODE_GX_FBSIZE; -} -#else unsigned int gx_frame_buffer_size(void) { unsigned int val; - /* FB size is reported by a virtual register */ + if (!geode_has_vsa2()) { + uint32_t hi, lo; + + /* The number of pages is (PMAX - PMIN)+1 */ + rdmsr(MSR_GLIU_P2D_RO0, lo, hi); + + /* PMAX */ + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20); + /* PMIN */ + val -= (lo & 0x000fffff); + val += 1; + + /* The page size is 4k */ + return (val << 12); + } + + /* FB size can be obtained from the VSA II */ /* Virtual register class = 0x02 */ /* VG_MEM_SIZE(512Kb units) = 0x00 */ - outw(0xFC53, 0xAC1C); - outw(0x0200, 0xAC1C); + outw(VSA_VR_UNLOCK, VSA_VRC_INDEX); + outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX); - val = (unsigned int)(inw(0xAC1E)) & 0xFFl; + val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFFl; return (val << 19); } -#endif int gx_line_delta(int xres, int bpp) { @@ -49,75 +58,76 @@ int gx_line_delta(int xres, int bpp) return (xres * (bpp >> 3) + 7) & ~0x7; } -static void gx_set_mode(struct fb_info *info) +void gx_set_mode(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 gcfg, dcfg; int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; /* Unlock the display controller registers. */ - readl(par->dc_regs + DC_UNLOCK); - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); - gcfg = readl(par->dc_regs + DC_GENERAL_CFG); - dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); + gcfg = read_dc(par, DC_GENERAL_CFG); + dcfg = read_dc(par, DC_DISPLAY_CFG); /* Disable the timing generator. */ - dcfg &= ~(DC_DCFG_TGEN); - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); + dcfg &= ~DC_DISPLAY_CFG_TGEN; + write_dc(par, DC_DISPLAY_CFG, dcfg); /* Wait for pending memory requests before disabling the FIFO load. */ udelay(100); /* Disable FIFO load and compression. */ - gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg &= ~(DC_GENERAL_CFG_DFLE | DC_GENERAL_CFG_CMPE | + DC_GENERAL_CFG_DECE); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Setup DCLK and its divisor. */ - par->vid_ops->set_dclk(info); + gx_set_dclk_frequency(info); /* * Setup new mode. */ /* Clear all unused feature bits. */ - gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; + gcfg &= DC_GENERAL_CFG_YUVM | DC_GENERAL_CFG_VDSE; dcfg = 0; /* Set FIFO priority (default 6/5) and enable. */ /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ - gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; + gcfg |= (6 << DC_GENERAL_CFG_DFHPEL_SHIFT) | + (5 << DC_GENERAL_CFG_DFHPSL_SHIFT) | DC_GENERAL_CFG_DFLE; /* Framebuffer start offset. */ - writel(0, par->dc_regs + DC_FB_ST_OFFSET); + write_dc(par, DC_FB_ST_OFFSET, 0); /* Line delta and line buffer length. */ - writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); - writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, - par->dc_regs + DC_LINE_SIZE); + write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3); + write_dc(par, DC_LINE_SIZE, + ((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2); /* Enable graphics and video data and unmask address lines. */ - dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; + dcfg |= DC_DISPLAY_CFG_GDEN | DC_DISPLAY_CFG_VDEN | + DC_DISPLAY_CFG_A20M | DC_DISPLAY_CFG_A18M; /* Set pixel format. */ switch (info->var.bits_per_pixel) { case 8: - dcfg |= DC_DCFG_DISP_MODE_8BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP; break; case 16: - dcfg |= DC_DCFG_DISP_MODE_16BPP; - dcfg |= DC_DCFG_16BPP_MODE_565; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP; break; case 32: - dcfg |= DC_DCFG_DISP_MODE_24BPP; - dcfg |= DC_DCFG_PALB; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP; + dcfg |= DC_DISPLAY_CFG_PALB; break; } /* Enable timing generator. */ - dcfg |= DC_DCFG_TGEN; + dcfg |= DC_DISPLAY_CFG_TGEN; /* Horizontal and vertical timings. */ hactive = info->var.xres; @@ -134,28 +144,34 @@ static void gx_set_mode(struct fb_info *info) vblankend = vsyncend + info->var.upper_margin; vtotal = vblankend; - writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); - writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); + write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | + ((htotal - 1) << 16)); + write_dc(par, DC_H_BLANK_TIMING, (hblankstart - 1) | + ((hblankend - 1) << 16)); + write_dc(par, DC_H_SYNC_TIMING, (hsyncstart - 1) | + ((hsyncend - 1) << 16)); - writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); - writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); + write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | + ((vtotal - 1) << 16)); + write_dc(par, DC_V_BLANK_TIMING, (vblankstart - 1) | + ((vblankend - 1) << 16)); + write_dc(par, DC_V_SYNC_TIMING, (vsyncstart - 1) | + ((vsyncend - 1) << 16)); /* Write final register values. */ - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_DISPLAY_CFG, dcfg); + write_dc(par, DC_GENERAL_CFG, gcfg); - par->vid_ops->configure_display(info); + gx_configure_display(info); /* Relock display controller registers */ - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); } -static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, - unsigned red, unsigned green, unsigned blue) +void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; int val; /* Hardware palette is in RGB 8-8-8 format. */ @@ -163,11 +179,6 @@ static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, val |= (green) & 0x00ff00; val |= (blue >> 8) & 0x0000ff; - writel(regno, par->dc_regs + DC_PAL_ADDRESS); - writel(val, par->dc_regs + DC_PAL_DATA); + write_dc(par, DC_PAL_ADDRESS, regno); + write_dc(par, DC_PAL_DATA, val); } - -struct geode_dc_ops gx_dc_ops = { - .set_mode = gx_set_mode, - .set_palette_reg = gx_set_hw_palette_reg, -}; diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h deleted file mode 100644 index 0af33f329e88..000000000000 --- a/drivers/video/geode/display_gx.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Geode GX display controller - * - * Copyright (C) 2006 Arcom Control Systems Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef __DISPLAY_GX_H__ -#define __DISPLAY_GX_H__ - -unsigned int gx_frame_buffer_size(void); -int gx_line_delta(int xres, int bpp); - -extern struct geode_dc_ops gx_dc_ops; - -/* MSR that tells us if a TFT or CRT is attached */ -#define GLD_MSR_CONFIG 0xC0002001 -#define GLD_MSR_CONFIG_DM_FP 0x40 - -/* Display controller registers */ - -#define DC_UNLOCK 0x00 -# define DC_UNLOCK_CODE 0x00004758 - -#define DC_GENERAL_CFG 0x04 -# define DC_GCFG_DFLE 0x00000001 -# define DC_GCFG_CURE 0x00000002 -# define DC_GCFG_ICNE 0x00000004 -# define DC_GCFG_VIDE 0x00000008 -# define DC_GCFG_CMPE 0x00000020 -# define DC_GCFG_DECE 0x00000040 -# define DC_GCFG_VGAE 0x00000080 -# define DC_GCFG_DFHPSL_MASK 0x00000F00 -# define DC_GCFG_DFHPSL_POS 8 -# define DC_GCFG_DFHPEL_MASK 0x0000F000 -# define DC_GCFG_DFHPEL_POS 12 -# define DC_GCFG_STFM 0x00010000 -# define DC_GCFG_FDTY 0x00020000 -# define DC_GCFG_VGAFT 0x00040000 -# define DC_GCFG_VDSE 0x00080000 -# define DC_GCFG_YUVM 0x00100000 -# define DC_GCFG_VFSL 0x00800000 -# define DC_GCFG_SIGE 0x01000000 -# define DC_GCFG_SGRE 0x02000000 -# define DC_GCFG_SGFR 0x04000000 -# define DC_GCFG_CRC_MODE 0x08000000 -# define DC_GCFG_DIAG 0x10000000 -# define DC_GCFG_CFRW 0x20000000 - -#define DC_DISPLAY_CFG 0x08 -# define DC_DCFG_TGEN 0x00000001 -# define DC_DCFG_GDEN 0x00000008 -# define DC_DCFG_VDEN 0x00000010 -# define DC_DCFG_TRUP 0x00000040 -# define DC_DCFG_DISP_MODE_MASK 0x00000300 -# define DC_DCFG_DISP_MODE_8BPP 0x00000000 -# define DC_DCFG_DISP_MODE_16BPP 0x00000100 -# define DC_DCFG_DISP_MODE_24BPP 0x00000200 -# define DC_DCFG_16BPP_MODE_MASK 0x00000c00 -# define DC_DCFG_16BPP_MODE_565 0x00000000 -# define DC_DCFG_16BPP_MODE_555 0x00000100 -# define DC_DCFG_16BPP_MODE_444 0x00000200 -# define DC_DCFG_DCEN 0x00080000 -# define DC_DCFG_PALB 0x02000000 -# define DC_DCFG_FRLK 0x04000000 -# define DC_DCFG_VISL 0x08000000 -# define DC_DCFG_FRSL 0x20000000 -# define DC_DCFG_A18M 0x40000000 -# define DC_DCFG_A20M 0x80000000 - -#define DC_FB_ST_OFFSET 0x10 - -#define DC_LINE_SIZE 0x30 -# define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff -# define DC_LINE_SIZE_FB_LINE_SIZE_POS 0 -# define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000 -# define DC_LINE_SIZE_CB_LINE_SIZE_POS 16 -# define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000 -# define DC_LINE_SIZE_VID_LINE_SIZE_POS 24 - -#define DC_GFX_PITCH 0x34 -# define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff -# define DC_GFX_PITCH_FB_PITCH_POS 0 -# define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000 -# define DC_GFX_PITCH_CB_PITCH_POS 16 - -#define DC_H_ACTIVE_TIMING 0x40 -#define DC_H_BLANK_TIMING 0x44 -#define DC_H_SYNC_TIMING 0x48 -#define DC_V_ACTIVE_TIMING 0x50 -#define DC_V_BLANK_TIMING 0x54 -#define DC_V_SYNC_TIMING 0x58 - -#define DC_PAL_ADDRESS 0x70 -#define DC_PAL_DATA 0x74 - -#define DC_GLIU0_MEM_OFFSET 0x84 -#endif /* !__DISPLAY_GX1_H__ */ diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h new file mode 100644 index 000000000000..16a96f8fd8c5 --- /dev/null +++ b/drivers/video/geode/gxfb.h @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2008 Andres Salomon <dilinger@debian.org> + * + * Geode GX2 header information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef _GXFB_H_ +#define _GXFB_H_ + +#include <linux/io.h> + +#define GP_REG_COUNT (0x50 / 4) +#define DC_REG_COUNT (0x90 / 4) +#define VP_REG_COUNT (0x138 / 8) +#define FP_REG_COUNT (0x68 / 8) + +#define DC_PAL_COUNT 0x104 + +struct gxfb_par { + int enable_crt; + void __iomem *dc_regs; + void __iomem *vid_regs; + void __iomem *gp_regs; +#ifdef CONFIG_PM + int powered_down; + + /* register state, for power management functionality */ + struct { + uint64_t padsel; + uint64_t dotpll; + } msr; + + uint32_t gp[GP_REG_COUNT]; + uint32_t dc[DC_REG_COUNT]; + uint64_t vp[VP_REG_COUNT]; + uint64_t fp[FP_REG_COUNT]; + + uint32_t pal[DC_PAL_COUNT]; +#endif +}; + +unsigned int gx_frame_buffer_size(void); +int gx_line_delta(int xres, int bpp); +void gx_set_mode(struct fb_info *info); +void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue); + +void gx_set_dclk_frequency(struct fb_info *info); +void gx_configure_display(struct fb_info *info); +int gx_blank_display(struct fb_info *info, int blank_mode); + +#ifdef CONFIG_PM +int gx_powerdown(struct fb_info *info); +int gx_powerup(struct fb_info *info); +#endif + + +/* Graphics Processor registers (table 6-23 from the data book) */ +enum gp_registers { + GP_DST_OFFSET = 0, + GP_SRC_OFFSET, + GP_STRIDE, + GP_WID_HEIGHT, + + GP_SRC_COLOR_FG, + GP_SRC_COLOR_BG, + GP_PAT_COLOR_0, + GP_PAT_COLOR_1, + + GP_PAT_COLOR_2, + GP_PAT_COLOR_3, + GP_PAT_COLOR_4, + GP_PAT_COLOR_5, + + GP_PAT_DATA_0, + GP_PAT_DATA_1, + GP_RASTER_MODE, + GP_VECTOR_MODE, + + GP_BLT_MODE, + GP_BLT_STATUS, + GP_HST_SRC, + GP_BASE_OFFSET, /* 0x4c */ +}; + +#define GP_BLT_STATUS_BLT_PENDING (1 << 2) +#define GP_BLT_STATUS_BLT_BUSY (1 << 0) + + +/* Display Controller registers (table 6-38 from the data book) */ +enum dc_registers { + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_RSVD_0, + + DC_FB_ST_OFFSET, + DC_CB_ST_OFFSET, + DC_CURS_ST_OFFSET, + DC_ICON_ST_OFFSET, + + DC_VID_Y_ST_OFFSET, + DC_VID_U_ST_OFFSET, + DC_VID_V_ST_OFFSET, + DC_RSVD_1, + + DC_LINE_SIZE, + DC_GFX_PITCH, + DC_VID_YUV_PITCH, + DC_RSVD_2, + + DC_H_ACTIVE_TIMING, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_RSVD_3, + + DC_V_ACTIVE_TIMING, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_RSVD_4, + + DC_CURSOR_X, + DC_CURSOR_Y, + DC_ICON_X, + DC_LINE_CNT, + + DC_PAL_ADDRESS, + DC_PAL_DATA, + DC_DFIFO_DIAG, + DC_CFIFO_DIAG, + + DC_VID_DS_DELTA, + DC_GLIU0_MEM_OFFSET, + DC_RSVD_5, + DC_DV_ACC, /* 0x8c */ +}; + +#define DC_UNLOCK_LOCK 0x00000000 +#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */ + +#define DC_GENERAL_CFG_YUVM (1 << 20) +#define DC_GENERAL_CFG_VDSE (1 << 19) +#define DC_GENERAL_CFG_DFHPEL_SHIFT 12 +#define DC_GENERAL_CFG_DFHPSL_SHIFT 8 +#define DC_GENERAL_CFG_DECE (1 << 6) +#define DC_GENERAL_CFG_CMPE (1 << 5) +#define DC_GENERAL_CFG_VIDE (1 << 3) +#define DC_GENERAL_CFG_ICNE (1 << 2) +#define DC_GENERAL_CFG_CURE (1 << 1) +#define DC_GENERAL_CFG_DFLE (1 << 0) + +#define DC_DISPLAY_CFG_A20M (1 << 31) +#define DC_DISPLAY_CFG_A18M (1 << 30) +#define DC_DISPLAY_CFG_PALB (1 << 25) +#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9) +#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8) +#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0) +#define DC_DISPLAY_CFG_VDEN (1 << 4) +#define DC_DISPLAY_CFG_GDEN (1 << 3) +#define DC_DISPLAY_CFG_TGEN (1 << 0) + + +/* + * Video Processor registers (table 6-54). + * There is space for 64 bit values, but we never use more than the + * lower 32 bits. The actual register save/restore code only bothers + * to restore those 32 bits. + */ +enum vp_registers { + VP_VCFG = 0, + VP_DCFG, + + VP_VX, + VP_VY, + + VP_VS, + VP_VCK, + + VP_VCM, + VP_GAR, + + VP_GDR, + VP_RSVD_0, + + VP_MISC, + VP_CCS, + + VP_RSVD_1, + VP_RSVD_2, + + VP_RSVD_3, + VP_VDC, + + VP_VCO, + VP_CRC, + + VP_CRC32, + VP_VDE, + + VP_CCK, + VP_CCM, + + VP_CC1, + VP_CC2, + + VP_A1X, + VP_A1Y, + + VP_A1C, + VP_A1T, + + VP_A2X, + VP_A2Y, + + VP_A2C, + VP_A2T, + + VP_A3X, + VP_A3Y, + + VP_A3C, + VP_A3T, + + VP_VRR, + VP_AWT, + + VP_VTM, /* 0x130 */ +}; + +#define VP_VCFG_VID_EN (1 << 0) + +#define VP_DCFG_DAC_VREF (1 << 26) +#define VP_DCFG_GV_GAM (1 << 21) +#define VP_DCFG_VG_CK (1 << 20) +#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16) +#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16)) +#define VP_DCFG_CRT_VSYNC_POL (1 << 9) +#define VP_DCFG_CRT_HSYNC_POL (1 << 8) +#define VP_DCFG_FP_DATA_EN (1 << 7) /* undocumented */ +#define VP_DCFG_FP_PWR_EN (1 << 6) /* undocumented */ +#define VP_DCFG_DAC_BL_EN (1 << 3) +#define VP_DCFG_VSYNC_EN (1 << 2) +#define VP_DCFG_HSYNC_EN (1 << 1) +#define VP_DCFG_CRT_EN (1 << 0) + +#define VP_MISC_GAM_EN (1 << 0) +#define VP_MISC_DACPWRDN (1 << 10) +#define VP_MISC_APWRDN (1 << 11) + + +/* + * Flat Panel registers (table 6-55). + * Also 64 bit registers; see above note about 32-bit handling. + */ + +/* we're actually in the VP register space, starting at address 0x400 */ +#define VP_FP_START 0x400 + +enum fp_registers { + FP_PT1 = 0, + FP_PT2, + + FP_PM, + FP_DFC, + + FP_BLFSR, + FP_RLFSR, + + FP_FMI, + FP_FMD, + + FP_RSVD_0, + FP_DCA, + + FP_DMD, + FP_CRC, + + FP_FBB, /* 0x460 */ +}; + +#define FP_PT1_VSIZE_SHIFT 16 /* undocumented? */ +#define FP_PT1_VSIZE_MASK 0x7FF0000 /* undocumented? */ + +#define FP_PT2_HSP (1 << 22) +#define FP_PT2_VSP (1 << 23) + +#define FP_PM_P (1 << 24) /* panel power on */ +#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */ +#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */ +#define FP_PM_PANEL_OFF (1 << 1) /* r/o */ +#define FP_PM_PANEL_ON (1 << 0) /* r/o */ + +#define FP_DFC_NFI ((1 << 4) | (1 << 5) | (1 << 6)) + + +/* register access functions */ + +static inline uint32_t read_gp(struct gxfb_par *par, int reg) +{ + return readl(par->gp_regs + 4*reg); +} + +static inline void write_gp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->gp_regs + 4*reg); +} + +static inline uint32_t read_dc(struct gxfb_par *par, int reg) +{ + return readl(par->dc_regs + 4*reg); +} + +static inline void write_dc(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->dc_regs + 4*reg); +} + +static inline uint32_t read_vp(struct gxfb_par *par, int reg) +{ + return readl(par->vid_regs + 8*reg); +} + +static inline void write_vp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vid_regs + 8*reg); +} + +static inline uint32_t read_fp(struct gxfb_par *par, int reg) +{ + return readl(par->vid_regs + 8*reg + VP_FP_START); +} + +static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vid_regs + 8*reg + VP_FP_START); +} + + +/* MSRs are defined in asm/geode.h; their bitfields are here */ + +#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3) +#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2) +#define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (1 << 1) + +#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ +#define MSR_GLCP_DOTPLL_BYPASS (1 << 15) +#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0) + +#define MSR_GX_MSR_PADSEL_MASK 0x3FFFFFFF /* undocumented? */ +#define MSR_GX_MSR_PADSEL_TFT 0x1FFFFFFF /* undocumented? */ + +#define MSR_GX_GLD_MSR_CONFIG_FP (1 << 3) + +#endif diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index cf841efa229a..de2b8f9876a5 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -28,17 +28,20 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> +#include <linux/console.h> +#include <linux/suspend.h> #include <linux/init.h> #include <linux/pci.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "display_gx.h" -#include "video_gx.h" +#include "gxfb.h" static char *mode_option; +static int vram; +static int vt_switch; /* Modes relevant to the GX (taken from modedb.c) */ -static const struct fb_videomode gx_modedb[] __initdata = { +static struct fb_videomode gx_modedb[] __initdata = { /* 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, @@ -105,6 +108,35 @@ static const struct fb_videomode gx_modedb[] __initdata = { FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; +#ifdef CONFIG_OLPC +#include <asm/olpc.h> + +static struct fb_videomode gx_dcon_modedb[] __initdata = { + /* The only mode the DCON has is 1200x900 */ + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 } +}; + +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + if (olpc_has_dcon()) { + *modedb = (struct fb_videomode *) gx_dcon_modedb; + *size = ARRAY_SIZE(gx_dcon_modedb); + } else { + *modedb = (struct fb_videomode *) gx_modedb; + *size = ARRAY_SIZE(gx_modedb); + } +} + +#else +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + *modedb = (struct fb_videomode *) gx_modedb; + *size = ARRAY_SIZE(gx_modedb); +} +#endif + static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xres > 1600 || var->yres > 1200) @@ -139,8 +171,6 @@ static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int gxfb_set_par(struct fb_info *info) { - struct geodefb_par *par = info->par; - if (info->var.bits_per_pixel > 8) { info->fix.visual = FB_VISUAL_TRUECOLOR; fb_dealloc_cmap(&info->cmap); @@ -151,7 +181,7 @@ static int gxfb_set_par(struct fb_info *info) info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel); - par->dc_ops->set_mode(info); + gx_set_mode(info); return 0; } @@ -167,8 +197,6 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct geodefb_par *par = info->par; - if (info->var.grayscale) { /* grayscale = 0.30*R + 0.59*G + 0.11*B */ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; @@ -191,7 +219,7 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= 256) return -EINVAL; - par->dc_ops->set_palette_reg(info, regno, red, green, blue); + gx_set_hw_palette_reg(info, regno, red, green, blue); } return 0; @@ -199,15 +227,12 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int gxfb_blank(int blank_mode, struct fb_info *info) { - struct geodefb_par *par = info->par; - - return par->vid_ops->blank_display(info, blank_mode); + return gx_blank_display(info, blank_mode); } static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) { - struct geodefb_par *par = info->par; - int fb_len; + struct gxfb_par *par = info->par; int ret; ret = pci_enable_device(dev); @@ -229,24 +254,31 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de if (!par->dc_regs) return -ENOMEM; - ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); + ret = pci_request_region(dev, 1, "gxfb (graphics processor)"); if (ret < 0) return ret; - if ((fb_len = gx_frame_buffer_size()) < 0) + par->gp_regs = ioremap(pci_resource_start(dev, 1), + pci_resource_len(dev, 1)); + + if (!par->gp_regs) return -ENOMEM; + + ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); + if (ret < 0) + return ret; + info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = fb_len; + info->fix.smem_len = vram ? vram : gx_frame_buffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) return -ENOMEM; - /* Set the 16MB aligned base address of the graphics memory region + /* Set the 16MiB aligned base address of the graphics memory region * in the display controller */ - writel(info->fix.smem_start & 0xFF000000, - par->dc_regs + DC_GLIU0_MEM_OFFSET); + write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000); - dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", + dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); return 0; @@ -266,11 +298,12 @@ static struct fb_ops gxfb_ops = { static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) { - struct geodefb_par *par; + struct gxfb_par *par; struct fb_info *info; /* Alloc enough space for the pseudo palette. */ - info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); + info = framebuffer_alloc(sizeof(struct gxfb_par) + sizeof(u32) * 16, + dev); if (!info) return NULL; @@ -296,29 +329,64 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) info->flags = FBINFO_DEFAULT; info->node = -1; - info->pseudo_palette = (void *)par + sizeof(struct geodefb_par); + info->pseudo_palette = (void *)par + sizeof(struct gxfb_par); info->var.grayscale = 0; return info; } +#ifdef CONFIG_PM +static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + gx_powerdown(info); + fb_set_suspend(info, 1); + release_console_sem(); + } + + /* there's no point in setting PCI states; we emulate PCI, so + * we don't end up getting power savings anyways */ + + return 0; +} + +static int gxfb_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + int ret; + + acquire_console_sem(); + ret = gx_powerup(info); + if (ret) { + printk(KERN_ERR "gxfb: power up failed!\n"); + return ret; + } + + fb_set_suspend(info, 0); + release_console_sem(); + return 0; +} +#endif + static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct geodefb_par *par; + struct gxfb_par *par; struct fb_info *info; int ret; unsigned long val; + struct fb_videomode *modedb_ptr; + unsigned int modedb_size; + info = gxfb_init_fbinfo(&pdev->dev); if (!info) return -ENOMEM; par = info->par; - /* GX display controller and GX video device. */ - par->dc_ops = &gx_dc_ops; - par->vid_ops = &gx_vid_ops; - if ((ret = gxfb_map_video_memory(info, pdev)) < 0) { dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); goto err; @@ -326,15 +394,16 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i /* Figure out if this is a TFT or CRT part */ - rdmsrl(GLD_MSR_CONFIG, val); + rdmsrl(MSR_GX_GLD_MSR_CONFIG, val); - if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP) + if ((val & MSR_GX_GLD_MSR_CONFIG_FP) == MSR_GX_GLD_MSR_CONFIG_FP) par->enable_crt = 0; else par->enable_crt = 1; + get_modedb(&modedb_ptr, &modedb_size); ret = fb_find_mode(&info->var, info, mode_option, - gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16); + modedb_ptr, modedb_size, NULL, 16); if (ret == 0 || ret == 4) { dev_err(&pdev->dev, "could not find valid video mode\n"); ret = -EINVAL; @@ -348,6 +417,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i gxfb_check_var(&info->var, info); gxfb_set_par(info); + pm_set_vt_switch(vt_switch); + if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; @@ -369,6 +440,10 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i iounmap(par->dc_regs); pci_release_region(pdev, 2); } + if (par->gp_regs) { + iounmap(par->gp_regs); + pci_release_region(pdev, 1); + } if (info) framebuffer_release(info); @@ -378,7 +453,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i static void gxfb_remove(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; unregister_framebuffer(info); @@ -391,15 +466,16 @@ static void gxfb_remove(struct pci_dev *pdev) iounmap(par->dc_regs); pci_release_region(pdev, 2); + iounmap(par->gp_regs); + pci_release_region(pdev, 1); + pci_set_drvdata(pdev, NULL); framebuffer_release(info); } static struct pci_device_id gxfb_id_table[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) }, { 0, } }; @@ -410,6 +486,10 @@ static struct pci_driver gxfb_driver = { .id_table = gxfb_id_table, .probe = gxfb_probe, .remove = gxfb_remove, +#ifdef CONFIG_PM + .suspend = gxfb_suspend, + .resume = gxfb_resume, +#endif }; #ifndef MODULE @@ -456,5 +536,11 @@ module_exit(gxfb_cleanup); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "video memory size"); + +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); + MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index ca13c48d19b0..3b9416f4ee20 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -3,17 +3,46 @@ #include <linux/fb.h> +#define GP_REG_COUNT (0x7c / 4) +#define DC_REG_COUNT (0xf0 / 4) +#define VP_REG_COUNT (0x158 / 8) +#define FP_REG_COUNT (0x60 / 8) + +#define DC_PAL_COUNT 0x104 +#define DC_HFILT_COUNT 0x100 +#define DC_VFILT_COUNT 0x100 +#define VP_COEFF_SIZE 0x1000 + #define OUTPUT_CRT 0x01 #define OUTPUT_PANEL 0x02 struct lxfb_par { int output; - int panel_width; - int panel_height; void __iomem *gp_regs; void __iomem *dc_regs; - void __iomem *df_regs; + void __iomem *vp_regs; +#ifdef CONFIG_PM + int powered_down; + + /* register state, for power mgmt functionality */ + struct { + uint64_t padsel; + uint64_t dotpll; + uint64_t dfglcfg; + uint64_t dcspare; + } msr; + + uint32_t gp[GP_REG_COUNT]; + uint32_t dc[DC_REG_COUNT]; + uint64_t vp[VP_REG_COUNT]; + uint64_t fp[FP_REG_COUNT]; + + uint32_t pal[DC_PAL_COUNT]; + uint32_t hcoeff[DC_HFILT_COUNT * 2]; + uint32_t vcoeff[DC_VFILT_COUNT]; + uint32_t vp_coeff[VP_COEFF_SIZE / 4]; +#endif }; static inline unsigned int lx_get_pitch(unsigned int xres, int bpp) @@ -29,171 +58,383 @@ int lx_blank_display(struct fb_info *, int); void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, unsigned int, unsigned int); -/* MSRS */ +#ifdef CONFIG_PM +int lx_powerdown(struct fb_info *info); +int lx_powerup(struct fb_info *info); +#endif + + +/* Graphics Processor registers (table 6-29 from the data book) */ +enum gp_registers { + GP_DST_OFFSET = 0, + GP_SRC_OFFSET, + GP_STRIDE, + GP_WID_HEIGHT, + + GP_SRC_COLOR_FG, + GP_SRC_COLOR_BG, + GP_PAT_COLOR_0, + GP_PAT_COLOR_1, + + GP_PAT_COLOR_2, + GP_PAT_COLOR_3, + GP_PAT_COLOR_4, + GP_PAT_COLOR_5, + + GP_PAT_DATA_0, + GP_PAT_DATA_1, + GP_RASTER_MODE, + GP_VECTOR_MODE, + + GP_BLT_MODE, + GP_BLT_STATUS, + GP_HST_SRC, + GP_BASE_OFFSET, + + GP_CMD_TOP, + GP_CMD_BOT, + GP_CMD_READ, + GP_CMD_WRITE, + + GP_CH3_OFFSET, + GP_CH3_MODE_STR, + GP_CH3_WIDHI, + GP_CH3_HSRC, + + GP_LUT_INDEX, + GP_LUT_DATA, + GP_INT_CNTRL, /* 0x78 */ +}; + +#define GP_BLT_STATUS_CE (1 << 4) /* cmd buf empty */ +#define GP_BLT_STATUS_PB (1 << 0) /* primative busy */ + + +/* Display Controller registers (table 6-47 from the data book) */ +enum dc_registers { + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_ARB_CFG, + + DC_FB_ST_OFFSET, + DC_CB_ST_OFFSET, + DC_CURS_ST_OFFSET, + DC_RSVD_0, + + DC_VID_Y_ST_OFFSET, + DC_VID_U_ST_OFFSET, + DC_VID_V_ST_OFFSET, + DC_DV_TOP, + + DC_LINE_SIZE, + DC_GFX_PITCH, + DC_VID_YUV_PITCH, + DC_RSVD_1, + + DC_H_ACTIVE_TIMING, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_RSVD_2, + + DC_V_ACTIVE_TIMING, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_FB_ACTIVE, + + DC_CURSOR_X, + DC_CURSOR_Y, + DC_RSVD_3, + DC_LINE_CNT, + + DC_PAL_ADDRESS, + DC_PAL_DATA, + DC_DFIFO_DIAG, + DC_CFIFO_DIAG, + + DC_VID_DS_DELTA, + DC_GLIU0_MEM_OFFSET, + DC_DV_CTL, + DC_DV_ACCESS, + + DC_GFX_SCALE, + DC_IRQ_FILT_CTL, + DC_FILT_COEFF1, + DC_FILT_COEFF2, + + DC_VBI_EVEN_CTL, + DC_VBI_ODD_CTL, + DC_VBI_HOR, + DC_VBI_LN_ODD, + + DC_VBI_LN_EVEN, + DC_VBI_PITCH, + DC_CLR_KEY, + DC_CLR_KEY_MASK, + + DC_CLR_KEY_X, + DC_CLR_KEY_Y, + DC_IRQ, + DC_RSVD_4, + + DC_RSVD_5, + DC_GENLK_CTL, + DC_VID_EVEN_Y_ST_OFFSET, + DC_VID_EVEN_U_ST_OFFSET, + + DC_VID_EVEN_V_ST_OFFSET, + DC_V_ACTIVE_EVEN_TIMING, + DC_V_BLANK_EVEN_TIMING, + DC_V_SYNC_EVEN_TIMING, /* 0xec */ +}; + +#define DC_UNLOCK_LOCK 0x00000000 +#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */ + +#define DC_GENERAL_CFG_FDTY (1 << 17) +#define DC_GENERAL_CFG_DFHPEL_SHIFT (12) +#define DC_GENERAL_CFG_DFHPSL_SHIFT (8) +#define DC_GENERAL_CFG_VGAE (1 << 7) +#define DC_GENERAL_CFG_DECE (1 << 6) +#define DC_GENERAL_CFG_CMPE (1 << 5) +#define DC_GENERAL_CFG_VIDE (1 << 3) +#define DC_GENERAL_CFG_DFLE (1 << 0) + +#define DC_DISPLAY_CFG_VISL (1 << 27) +#define DC_DISPLAY_CFG_PALB (1 << 25) +#define DC_DISPLAY_CFG_DCEN (1 << 24) +#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9) +#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8) +#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0) +#define DC_DISPLAY_CFG_TRUP (1 << 6) +#define DC_DISPLAY_CFG_VDEN (1 << 4) +#define DC_DISPLAY_CFG_GDEN (1 << 3) +#define DC_DISPLAY_CFG_TGEN (1 << 0) + +#define DC_DV_TOP_DV_TOP_EN (1 << 0) + +#define DC_DV_CTL_DV_LINE_SIZE ((1 << 10) | (1 << 11)) +#define DC_DV_CTL_DV_LINE_SIZE_1K (0) +#define DC_DV_CTL_DV_LINE_SIZE_2K (1 << 10) +#define DC_DV_CTL_DV_LINE_SIZE_4K (1 << 11) +#define DC_DV_CTL_DV_LINE_SIZE_8K ((1 << 10) | (1 << 11)) +#define DC_DV_CTL_CLEAR_DV_RAM (1 << 0) + +#define DC_IRQ_FILT_CTL_H_FILT_SEL (1 << 10) + +#define DC_CLR_KEY_CLR_KEY_EN (1 << 24) + +#define DC_IRQ_VIP_VSYNC_IRQ_STATUS (1 << 21) /* undocumented? */ +#define DC_IRQ_STATUS (1 << 20) /* undocumented? */ +#define DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK (1 << 1) +#define DC_IRQ_MASK (1 << 0) -#define MSR_LX_GLD_CONFIG 0x48002001 -#define MSR_LX_GLCP_DOTPLL 0x4c000015 -#define MSR_LX_DF_PADSEL 0x48002011 -#define MSR_LX_DC_SPARE 0x80000011 -#define MSR_LX_DF_GLCONFIG 0x48002001 - -#define MSR_LX_GLIU0_P2D_RO0 0x10000029 - -#define GLCP_DOTPLL_RESET (1 << 0) -#define GLCP_DOTPLL_BYPASS (1 << 15) -#define GLCP_DOTPLL_HALFPIX (1 << 24) -#define GLCP_DOTPLL_LOCK (1 << 25) - -#define DF_CONFIG_OUTPUT_MASK 0x38 -#define DF_OUTPUT_PANEL 0x08 -#define DF_OUTPUT_CRT 0x00 -#define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15) - -#define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF -#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F - -#define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800 -#define DC_SPARE_VFIFO_ARB_SELECT 0x00000400 -#define DC_SPARE_WM_LPEN_OVRD 0x00000200 -#define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100 -#define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080 -#define DC_SPARE_DISABLE_VFIFO_WM 0x00000040 -#define DC_SPARE_DISABLE_CWD_CHECK 0x00000020 -#define DC_SPARE_PIX8_PAN_FIX 0x00000010 -#define DC_SPARE_FIRST_REQ_MASK 0x00000002 - -/* Registers */ - -#define DC_UNLOCK 0x00 -#define DC_UNLOCK_CODE 0x4758 +#define DC_GENLK_CTL_FLICK_SEL_MASK (0x0F << 28) +#define DC_GENLK_CTL_ALPHA_FLICK_EN (1 << 25) +#define DC_GENLK_CTL_FLICK_EN (1 << 24) +#define DC_GENLK_CTL_GENLK_EN (1 << 18) -#define DC_GENERAL_CFG 0x04 -#define DC_GCFG_DFLE (1 << 0) -#define DC_GCFG_VIDE (1 << 3) -#define DC_GCFG_VGAE (1 << 7) -#define DC_GCFG_CMPE (1 << 5) -#define DC_GCFG_DECE (1 << 6) -#define DC_GCFG_FDTY (1 << 17) -#define DC_DISPLAY_CFG 0x08 -#define DC_DCFG_TGEN (1 << 0) -#define DC_DCFG_GDEN (1 << 3) -#define DC_DCFG_VDEN (1 << 4) -#define DC_DCFG_TRUP (1 << 6) -#define DC_DCFG_DCEN (1 << 24) -#define DC_DCFG_PALB (1 << 25) -#define DC_DCFG_VISL (1 << 27) +/* + * Video Processor registers (table 6-71). + * There is space for 64 bit values, but we never use more than the + * lower 32 bits. The actual register save/restore code only bothers + * to restore those 32 bits. + */ +enum vp_registers { + VP_VCFG = 0, + VP_DCFG, -#define DC_DCFG_16BPP 0x0 + VP_VX, + VP_VY, -#define DC_DCFG_DISP_MODE_MASK 0x00000300 -#define DC_DCFG_DISP_MODE_8BPP 0x00000000 -#define DC_DCFG_DISP_MODE_16BPP 0x00000100 -#define DC_DCFG_DISP_MODE_24BPP 0x00000200 -#define DC_DCFG_DISP_MODE_32BPP 0x00000300 + VP_SCL, + VP_VCK, + VP_VCM, + VP_PAR, -#define DC_ARB_CFG 0x0C + VP_PDR, + VP_SLR, -#define DC_FB_START 0x10 -#define DC_CB_START 0x14 -#define DC_CURSOR_START 0x18 + VP_MISC, + VP_CCS, -#define DC_DV_TOP 0x2C -#define DC_DV_TOP_ENABLE (1 << 0) + VP_VYS, + VP_VXS, -#define DC_LINE_SIZE 0x30 -#define DC_GRAPHICS_PITCH 0x34 -#define DC_H_ACTIVE_TIMING 0x40 -#define DC_H_BLANK_TIMING 0x44 -#define DC_H_SYNC_TIMING 0x48 -#define DC_V_ACTIVE_TIMING 0x50 -#define DC_V_BLANK_TIMING 0x54 -#define DC_V_SYNC_TIMING 0x58 -#define DC_FB_ACTIVE 0x5C + VP_RSVD_0, + VP_VDC, + + VP_RSVD_1, + VP_CRC, + + VP_CRC32, + VP_VDE, + + VP_CCK, + VP_CCM, + + VP_CC1, + VP_CC2, + + VP_A1X, + VP_A1Y, + + VP_A1C, + VP_A1T, + + VP_A2X, + VP_A2Y, + + VP_A2C, + VP_A2T, + + VP_A3X, + VP_A3Y, + + VP_A3C, + VP_A3T, + + VP_VRR, + VP_AWT, + + VP_VTM, + VP_VYE, + + VP_A1YE, + VP_A2YE, + + VP_A3YE, /* 0x150 */ + + VP_VCR = 0x1000, /* 0x1000 - 0x1fff */ +}; -#define DC_PAL_ADDRESS 0x70 -#define DC_PAL_DATA 0x74 +#define VP_VCFG_VID_EN (1 << 0) -#define DC_PHY_MEM_OFFSET 0x84 +#define VP_DCFG_GV_GAM (1 << 21) +#define VP_DCFG_PWR_SEQ_DELAY ((1 << 17) | (1 << 18) | (1 << 19)) +#define VP_DCFG_PWR_SEQ_DELAY_DEFAULT (1 << 19) /* undocumented */ +#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16)) +#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16) +#define VP_DCFG_CRT_VSYNC_POL (1 << 9) +#define VP_DCFG_CRT_HSYNC_POL (1 << 8) +#define VP_DCFG_DAC_BL_EN (1 << 3) +#define VP_DCFG_VSYNC_EN (1 << 2) +#define VP_DCFG_HSYNC_EN (1 << 1) +#define VP_DCFG_CRT_EN (1 << 0) -#define DC_DV_CTL 0x88 -#define DC_DV_LINE_SIZE_MASK 0x00000C00 -#define DC_DV_LINE_SIZE_1024 0x00000000 -#define DC_DV_LINE_SIZE_2048 0x00000400 -#define DC_DV_LINE_SIZE_4096 0x00000800 -#define DC_DV_LINE_SIZE_8192 0x00000C00 +#define VP_MISC_APWRDN (1 << 11) +#define VP_MISC_DACPWRDN (1 << 10) +#define VP_MISC_BYP_BOTH (1 << 0) -#define DC_GFX_SCALE 0x90 -#define DC_IRQ_FILT_CTL 0x94 +/* + * Flat Panel registers (table 6-71). + * Also 64 bit registers; see above note about 32-bit handling. + */ +/* we're actually in the VP register space, starting at address 0x400 */ +#define VP_FP_START 0x400 -#define DC_IRQ 0xC8 -#define DC_IRQ_MASK (1 << 0) -#define DC_VSYNC_IRQ_MASK (1 << 1) -#define DC_IRQ_STATUS (1 << 20) -#define DC_VSYNC_IRQ_STATUS (1 << 21) - -#define DC_GENLCK_CTRL 0xD4 -#define DC_GENLCK_ENABLE (1 << 18) -#define DC_GC_ALPHA_FLICK_ENABLE (1 << 25) -#define DC_GC_FLICKER_FILTER_ENABLE (1 << 24) -#define DC_GC_FLICKER_FILTER_MASK (0x0F << 28) - -#define DC_COLOR_KEY 0xB8 -#define DC_CLR_KEY_ENABLE (1 << 24) - - -#define DC3_DV_LINE_SIZE_MASK 0x00000C00 -#define DC3_DV_LINE_SIZE_1024 0x00000000 -#define DC3_DV_LINE_SIZE_2048 0x00000400 -#define DC3_DV_LINE_SIZE_4096 0x00000800 -#define DC3_DV_LINE_SIZE_8192 0x00000C00 - -#define DF_VIDEO_CFG 0x0 -#define DF_VCFG_VID_EN (1 << 0) - -#define DF_DISPLAY_CFG 0x08 - -#define DF_DCFG_CRT_EN (1 << 0) -#define DF_DCFG_HSYNC_EN (1 << 1) -#define DF_DCFG_VSYNC_EN (1 << 2) -#define DF_DCFG_DAC_BL_EN (1 << 3) -#define DF_DCFG_CRT_HSYNC_POL (1 << 8) -#define DF_DCFG_CRT_VSYNC_POL (1 << 9) -#define DF_DCFG_GV_PAL_BYP (1 << 21) +enum fp_registers { + FP_PT1 = 0, + FP_PT2, -#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000 -#define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000 + FP_PM, + FP_DFC, -#define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000 -#define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000 + FP_RSVD_0, + FP_RSVD_1, -#define DF_MISC 0x50 + FP_RSVD_2, + FP_RSVD_3, + + FP_RSVD_4, + FP_DCA, + + FP_DMD, + FP_CRC, /* 0x458 */ +}; + +#define FP_PT2_SCRC (1 << 27) /* shfclk free */ + +#define FP_PM_P (1 << 24) /* panel power ctl */ +#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */ +#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */ +#define FP_PM_PANEL_OFF (1 << 1) /* r/o */ +#define FP_PM_PANEL_ON (1 << 0) /* r/o */ + +#define FP_DFC_BC ((1 << 4) | (1 << 5) | (1 << 6)) + + +/* register access functions */ + +static inline uint32_t read_gp(struct lxfb_par *par, int reg) +{ + return readl(par->gp_regs + 4*reg); +} + +static inline void write_gp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->gp_regs + 4*reg); +} + +static inline uint32_t read_dc(struct lxfb_par *par, int reg) +{ + return readl(par->dc_regs + 4*reg); +} + +static inline void write_dc(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->dc_regs + 4*reg); +} + +static inline uint32_t read_vp(struct lxfb_par *par, int reg) +{ + return readl(par->vp_regs + 8*reg); +} + +static inline void write_vp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vp_regs + 8*reg); +} + +static inline uint32_t read_fp(struct lxfb_par *par, int reg) +{ + return readl(par->vp_regs + 8*reg + VP_FP_START); +} + +static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vp_regs + 8*reg + VP_FP_START); +} -#define DF_MISC_GAM_BYPASS (1 << 0) -#define DF_MISC_DAC_PWRDN (1 << 10) -#define DF_MISC_A_PWRDN (1 << 11) -#define DF_PAR 0x38 -#define DF_PDR 0x40 -#define DF_ALPHA_CONTROL_1 0xD8 -#define DF_VIDEO_REQUEST 0x120 +/* MSRs are defined in asm/geode.h; their bitfields are here */ -#define DF_PANEL_TIM1 0x400 -#define DF_DEFAULT_TFT_PMTIM1 0x0 +#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ +#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24) +#define MSR_GLCP_DOTPLL_BYPASS (1 << 15) +#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0) -#define DF_PANEL_TIM2 0x408 -#define DF_DEFAULT_TFT_PMTIM2 0x08000000 +/* note: this is actually the VP's GLD_MSR_CONFIG */ +#define MSR_LX_GLD_MSR_CONFIG_FMT ((1 << 3) | (1 << 4) | (1 << 5)) +#define MSR_LX_GLD_MSR_CONFIG_FMT_FP (1 << 3) +#define MSR_LX_GLD_MSR_CONFIG_FMT_CRT (0) +#define MSR_LX_GLD_MSR_CONFIG_FPC (1 << 15) /* FP *and* CRT */ -#define DF_FP_PM 0x410 -#define DF_FP_PM_P (1 << 24) +#define MSR_LX_MSR_PADSEL_TFT_SEL_LOW 0xDFFFFFFF /* ??? */ +#define MSR_LX_MSR_PADSEL_TFT_SEL_HIGH 0x0000003F /* ??? */ -#define DF_DITHER_CONTROL 0x418 -#define DF_DEFAULT_TFT_DITHCTL 0x00000070 -#define GP_BLT_STATUS 0x44 -#define GP_BS_BLT_BUSY (1 << 0) -#define GP_BS_CB_EMPTY (1 << 4) +#define MSR_LX_SPARE_MSR_DIS_CFIFO_HGO (1 << 11) /* undocumented */ +#define MSR_LX_SPARE_MSR_VFIFO_ARB_SEL (1 << 10) /* undocumented */ +#define MSR_LX_SPARE_MSR_WM_LPEN_OVRD (1 << 9) /* undocumented */ +#define MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M (1 << 8) /* undocumented */ +#define MSR_LX_SPARE_MSR_DIS_INIT_V_PRI (1 << 7) /* undocumented */ +#define MSR_LX_SPARE_MSR_DIS_VIFO_WM (1 << 6) +#define MSR_LX_SPARE_MSR_DIS_CWD_CHECK (1 << 5) /* undocumented */ +#define MSR_LX_SPARE_MSR_PIX8_PAN_FIX (1 << 4) /* undocumented */ +#define MSR_LX_SPARE_MSR_FIRST_REQ_MASK (1 << 1) /* undocumented */ #endif diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index eb6b88171538..2cd9b74d2225 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -17,6 +17,7 @@ #include <linux/console.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/suspend.h> #include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> @@ -27,14 +28,15 @@ static char *mode_option; static int noclear, nopanel, nocrt; -static int fbsize; +static int vram; +static int vt_switch; /* Most of these modes are sorted in ascending order, but * since the first entry in this table is the "default" mode, * we try to make it something sane - 640x480-60 is sane */ -static const struct fb_videomode geode_modedb[] __initdata = { +static struct fb_videomode geode_modedb[] __initdata = { /* 640x480-60 */ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, @@ -215,6 +217,35 @@ static const struct fb_videomode geode_modedb[] __initdata = { 0, FB_VMODE_NONINTERLACED, 0 }, }; +#ifdef CONFIG_OLPC +#include <asm/olpc.h> + +static struct fb_videomode olpc_dcon_modedb[] __initdata = { + /* The only mode the DCON has is 1200x900 */ + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 } +}; + +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + if (olpc_has_dcon()) { + *modedb = (struct fb_videomode *) olpc_dcon_modedb; + *size = ARRAY_SIZE(olpc_dcon_modedb); + } else { + *modedb = (struct fb_videomode *) geode_modedb; + *size = ARRAY_SIZE(geode_modedb); + } +} + +#else +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + *modedb = (struct fb_videomode *) geode_modedb; + *size = ARRAY_SIZE(geode_modedb); +} +#endif + static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xres > 1920 || var->yres > 1440) @@ -333,13 +364,13 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (ret) return ret; - ret = pci_request_region(dev, 3, "lxfb-vip"); + ret = pci_request_region(dev, 3, "lxfb-vp"); if (ret) return ret; info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size(); + info->fix.smem_len = vram ? vram : lx_framebuffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); @@ -360,18 +391,15 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (par->dc_regs == NULL) return ret; - par->df_regs = ioremap(pci_resource_start(dev, 3), + par->vp_regs = ioremap(pci_resource_start(dev, 3), pci_resource_len(dev, 3)); - if (par->df_regs == NULL) + if (par->vp_regs == NULL) return ret; - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); - - writel(info->fix.smem_start & 0xFF000000, - par->dc_regs + DC_PHY_MEM_OFFSET); - - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); @@ -431,6 +459,45 @@ static struct fb_info * __init lxfb_init_fbinfo(struct device *dev) return info; } +#ifdef CONFIG_PM +static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + lx_powerdown(info); + fb_set_suspend(info, 1); + release_console_sem(); + } + + /* there's no point in setting PCI states; we emulate PCI, so + * we don't end up getting power savings anyways */ + + return 0; +} + +static int lxfb_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + int ret; + + acquire_console_sem(); + ret = lx_powerup(info); + if (ret) { + printk(KERN_ERR "lxfb: power up failed!\n"); + return ret; + } + + fb_set_suspend(info, 0); + release_console_sem(); + return 0; +} +#else +#define lxfb_suspend NULL +#define lxfb_resume NULL +#endif + static int __init lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -439,7 +506,7 @@ static int __init lxfb_probe(struct pci_dev *pdev, int ret; struct fb_videomode *modedb_ptr; - int modedb_size; + unsigned int modedb_size; info = lxfb_init_fbinfo(&pdev->dev); @@ -464,9 +531,7 @@ static int __init lxfb_probe(struct pci_dev *pdev, /* Set up the mode database */ - modedb_ptr = (struct fb_videomode *) geode_modedb; - modedb_size = ARRAY_SIZE(geode_modedb); - + get_modedb(&modedb_ptr, &modedb_size); ret = fb_find_mode(&info->var, info, mode_option, modedb_ptr, modedb_size, NULL, 16); @@ -487,6 +552,8 @@ static int __init lxfb_probe(struct pci_dev *pdev, lxfb_check_var(&info->var, info); lxfb_set_par(info); + pm_set_vt_switch(vt_switch); + if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; @@ -510,8 +577,8 @@ err: iounmap(par->dc_regs); pci_release_region(pdev, 2); } - if (par->df_regs) { - iounmap(par->df_regs); + if (par->vp_regs) { + iounmap(par->vp_regs); pci_release_region(pdev, 3); } @@ -537,7 +604,7 @@ static void lxfb_remove(struct pci_dev *pdev) iounmap(par->dc_regs); pci_release_region(pdev, 2); - iounmap(par->df_regs); + iounmap(par->vp_regs); pci_release_region(pdev, 3); pci_set_drvdata(pdev, NULL); @@ -556,6 +623,8 @@ static struct pci_driver lxfb_driver = { .id_table = lxfb_id_table, .probe = lxfb_probe, .remove = lxfb_remove, + .suspend = lxfb_suspend, + .resume = lxfb_resume, }; #ifndef MODULE @@ -570,9 +639,7 @@ static int __init lxfb_setup(char *options) if (!*opt) continue; - if (!strncmp(opt, "fbsize:", 7)) - fbsize = simple_strtoul(opt+7, NULL, 0); - else if (!strcmp(opt, "noclear")) + if (!strcmp(opt, "noclear")) noclear = 1; else if (!strcmp(opt, "nopanel")) nopanel = 1; @@ -609,8 +676,11 @@ module_exit(lxfb_cleanup); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); -module_param(fbsize, int, 0); -MODULE_PARM_DESC(fbsize, "video memory size"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "video memory size"); + +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index 4fbc99be96ef..cd9d4cc26954 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -13,6 +13,7 @@ #include <linux/fb.h> #include <linux/uaccess.h> #include <linux/delay.h> +#include <asm/geode.h> #include "lxfb.h" @@ -34,35 +35,85 @@ static const struct { unsigned int pllval; unsigned int freq; } pll_table[] = { - { 0x000031AC, 24923 }, - { 0x0000215D, 25175 }, - { 0x00001087, 27000 }, - { 0x0000216C, 28322 }, - { 0x0000218D, 28560 }, - { 0x000010C9, 31200 }, - { 0x00003147, 31500 }, - { 0x000010A7, 33032 }, - { 0x00002159, 35112 }, - { 0x00004249, 35500 }, - { 0x00000057, 36000 }, - { 0x0000219A, 37889 }, - { 0x00002158, 39168 }, - { 0x00000045, 40000 }, - { 0x00000089, 43163 }, - { 0x000010E7, 44900 }, - { 0x00002136, 45720 }, - { 0x00003207, 49500 }, - { 0x00002187, 50000 }, - { 0x00004286, 56250 }, - { 0x000010E5, 60065 }, - { 0x00004214, 65000 }, - { 0x00001105, 68179 }, - { 0x000031E4, 74250 }, - { 0x00003183, 75000 }, - { 0x00004284, 78750 }, - { 0x00001104, 81600 }, - { 0x00006363, 94500 }, - { 0x00005303, 97520 }, + { 0x000131AC, 6231 }, + { 0x0001215D, 6294 }, + { 0x00011087, 6750 }, + { 0x0001216C, 7081 }, + { 0x0001218D, 7140 }, + { 0x000110C9, 7800 }, + { 0x00013147, 7875 }, + { 0x000110A7, 8258 }, + { 0x00012159, 8778 }, + { 0x00014249, 8875 }, + { 0x00010057, 9000 }, + { 0x0001219A, 9472 }, + { 0x00012158, 9792 }, + { 0x00010045, 10000 }, + { 0x00010089, 10791 }, + { 0x000110E7, 11225 }, + { 0x00012136, 11430 }, + { 0x00013207, 12375 }, + { 0x00012187, 12500 }, + { 0x00014286, 14063 }, + { 0x000110E5, 15016 }, + { 0x00014214, 16250 }, + { 0x00011105, 17045 }, + { 0x000131E4, 18563 }, + { 0x00013183, 18750 }, + { 0x00014284, 19688 }, + { 0x00011104, 20400 }, + { 0x00016363, 23625 }, + { 0x00015303, 24380 }, + { 0x000031AC, 24923 }, + { 0x0000215D, 25175 }, + { 0x00001087, 27000 }, + { 0x0000216C, 28322 }, + { 0x0000218D, 28560 }, + { 0x00010041, 29913 }, + { 0x000010C9, 31200 }, + { 0x00003147, 31500 }, + { 0x000141A1, 32400 }, + { 0x000010A7, 33032 }, + { 0x00012182, 33375 }, + { 0x000141B1, 33750 }, + { 0x00002159, 35112 }, + { 0x00004249, 35500 }, + { 0x00000057, 36000 }, + { 0x000141E1, 37125 }, + { 0x0000219A, 37889 }, + { 0x00002158, 39168 }, + { 0x00000045, 40000 }, + { 0x000131A1, 40500 }, + { 0x00010061, 42301 }, + { 0x00000089, 43163 }, + { 0x00012151, 43875 }, + { 0x000010E7, 44900 }, + { 0x00002136, 45720 }, + { 0x000152E1, 47250 }, + { 0x00010071, 48000 }, + { 0x00003207, 49500 }, + { 0x00002187, 50000 }, + { 0x00014291, 50625 }, + { 0x00011101, 51188 }, + { 0x00017481, 54563 }, + { 0x00004286, 56250 }, + { 0x00014170, 57375 }, + { 0x00016210, 58500 }, + { 0x000010E5, 60065 }, + { 0x00013140, 62796 }, + { 0x00004214, 65000 }, + { 0x00016250, 65250 }, + { 0x00001105, 68179 }, + { 0x000141C0, 69600 }, + { 0x00015220, 70160 }, + { 0x00010050, 72000 }, + { 0x000031E4, 74250 }, + { 0x00003183, 75000 }, + { 0x00004284, 78750 }, + { 0x00012130, 80052 }, + { 0x00001104, 81600 }, + { 0x00006363, 94500 }, + { 0x00005303, 97520 }, { 0x00002183, 100187 }, { 0x00002122, 101420 }, { 0x00001081, 108000 }, @@ -101,16 +152,16 @@ static void lx_set_dotpll(u32 pllval) u32 dotpll_lo, dotpll_hi; int i; - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); - if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) + if ((dotpll_lo & MSR_GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) return; dotpll_hi = pllval; - dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX); - dotpll_lo |= GLCP_DOTPLL_RESET; + dotpll_lo &= ~(MSR_GLCP_DOTPLL_BYPASS | MSR_GLCP_DOTPLL_HALFPIX); + dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); /* Wait 100us for the PLL to lock */ @@ -119,15 +170,15 @@ static void lx_set_dotpll(u32 pllval) /* Now, loop for the lock bit */ for (i = 0; i < 1000; i++) { - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); - if (dotpll_lo & GLCP_DOTPLL_LOCK) + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) break; } /* Clear the reset bit */ - dotpll_lo &= ~GLCP_DOTPLL_RESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); } /* Set the clock based on the frequency specified by the current mode */ @@ -137,7 +188,7 @@ static void lx_set_clock(struct fb_info *info) unsigned int diff, min, best = 0; unsigned int freq, i; - freq = (unsigned int) (0x3b9aca00 / info->var.pixclock); + freq = (unsigned int) (1000000000 / info->var.pixclock); min = abs(pll_table[0].freq - freq); @@ -149,7 +200,7 @@ static void lx_set_clock(struct fb_info *info) } } - lx_set_dotpll(pll_table[best].pllval & 0x7FFF); + lx_set_dotpll(pll_table[best].pllval & 0x00017FFF); } static void lx_graphics_disable(struct fb_info *info) @@ -159,63 +210,62 @@ static void lx_graphics_disable(struct fb_info *info) /* Note: This assumes that the video is in a quitet state */ - writel(0, par->df_regs + DF_ALPHA_CONTROL_1); - writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32); - writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64); + write_vp(par, VP_A1T, 0); + write_vp(par, VP_A2T, 0); + write_vp(par, VP_A3T, 0); /* Turn off the VGA and video enable */ - val = readl (par->dc_regs + DC_GENERAL_CFG) & - ~(DC_GCFG_VGAE | DC_GCFG_VIDE); + val = read_dc(par, DC_GENERAL_CFG) & ~(DC_GENERAL_CFG_VGAE | + DC_GENERAL_CFG_VIDE); - writel(val, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_GENERAL_CFG, val); - val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN; - writel(val, par->df_regs + DF_VIDEO_CFG); + val = read_vp(par, VP_VCFG) & ~VP_VCFG_VID_EN; + write_vp(par, VP_VCFG, val); - writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK | - DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS, - par->dc_regs + DC_IRQ); + write_dc(par, DC_IRQ, DC_IRQ_MASK | DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK | + DC_IRQ_STATUS | DC_IRQ_VIP_VSYNC_IRQ_STATUS); - val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE; - writel(val, par->dc_regs + DC_GENLCK_CTRL); + val = read_dc(par, DC_GENLK_CTL) & ~DC_GENLK_CTL_GENLK_EN; + write_dc(par, DC_GENLK_CTL, val); - val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE; - writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY); + val = read_dc(par, DC_CLR_KEY); + write_dc(par, DC_CLR_KEY, val & ~DC_CLR_KEY_CLR_KEY_EN); - /* We don't actually blank the panel, due to the long latency - involved with bringing it back */ + /* turn off the panel */ + write_fp(par, FP_PM, read_fp(par, FP_PM) & ~FP_PM_P); - val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN; - writel(val, par->df_regs + DF_MISC); + val = read_vp(par, VP_MISC) | VP_MISC_DACPWRDN; + write_vp(par, VP_MISC, val); /* Turn off the display */ - val = readl(par->df_regs + DF_DISPLAY_CFG); - writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN | - DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG); + val = read_vp(par, VP_DCFG); + write_vp(par, VP_DCFG, val & ~(VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN)); - gcfg = readl(par->dc_regs + DC_GENERAL_CFG); - gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg = read_dc(par, DC_GENERAL_CFG); + gcfg &= ~(DC_GENERAL_CFG_CMPE | DC_GENERAL_CFG_DECE); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Turn off the TGEN */ - val = readl(par->dc_regs + DC_DISPLAY_CFG); - val &= ~DC_DCFG_TGEN; - writel(val, par->dc_regs + DC_DISPLAY_CFG); + val = read_dc(par, DC_DISPLAY_CFG); + val &= ~DC_DISPLAY_CFG_TGEN; + write_dc(par, DC_DISPLAY_CFG, val); /* Wait 1000 usecs to ensure that the TGEN is clear */ udelay(1000); /* Turn off the FIFO loader */ - gcfg &= ~DC_GCFG_DFLE; - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg &= ~DC_GENERAL_CFG_DFLE; + write_dc(par, DC_GENERAL_CFG, gcfg); /* Lastly, wait for the GP to go idle */ do { - val = readl(par->gp_regs + GP_BLT_STATUS); - } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY)); + val = read_gp(par, GP_BLT_STATUS); + } while ((val & GP_BLT_STATUS_PB) || !(val & GP_BLT_STATUS_CE)); } static void lx_graphics_enable(struct fb_info *info) @@ -224,80 +274,85 @@ static void lx_graphics_enable(struct fb_info *info) u32 temp, config; /* Set the video request register */ - writel(0, par->df_regs + DF_VIDEO_REQUEST); + write_vp(par, VP_VRR, 0); /* Set up the polarities */ - config = readl(par->df_regs + DF_DISPLAY_CFG); + config = read_vp(par, VP_DCFG); - config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK | - DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL); + config &= ~(VP_DCFG_CRT_SYNC_SKW | VP_DCFG_PWR_SEQ_DELAY | + VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL); - config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT | - DF_DCFG_GV_PAL_BYP); + config |= (VP_DCFG_CRT_SYNC_SKW_DEFAULT | VP_DCFG_PWR_SEQ_DELAY_DEFAULT + | VP_DCFG_GV_GAM); if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - config |= DF_DCFG_CRT_HSYNC_POL; + config |= VP_DCFG_CRT_HSYNC_POL; if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - config |= DF_DCFG_CRT_VSYNC_POL; + config |= VP_DCFG_CRT_VSYNC_POL; if (par->output & OUTPUT_PANEL) { u32 msrlo, msrhi; - writel(DF_DEFAULT_TFT_PMTIM1, - par->df_regs + DF_PANEL_TIM1); - writel(DF_DEFAULT_TFT_PMTIM2, - par->df_regs + DF_PANEL_TIM2); - writel(DF_DEFAULT_TFT_DITHCTL, - par->df_regs + DF_DITHER_CONTROL); + write_fp(par, FP_PT1, 0); + write_fp(par, FP_PT2, FP_PT2_SCRC); + write_fp(par, FP_DFC, FP_DFC_BC); - msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW; - msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH; + msrlo = MSR_LX_MSR_PADSEL_TFT_SEL_LOW; + msrhi = MSR_LX_MSR_PADSEL_TFT_SEL_HIGH; - wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi); + wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi); } if (par->output & OUTPUT_CRT) { - config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | - DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN; + config |= VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN; } - writel(config, par->df_regs + DF_DISPLAY_CFG); + write_vp(par, VP_DCFG, config); /* Turn the CRT dacs back on */ if (par->output & OUTPUT_CRT) { - temp = readl(par->df_regs + DF_MISC); - temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN); - writel(temp, par->df_regs + DF_MISC); + temp = read_vp(par, VP_MISC); + temp &= ~(VP_MISC_DACPWRDN | VP_MISC_APWRDN); + write_vp(par, VP_MISC, temp); } /* Turn the panel on (if it isn't already) */ - - if (par->output & OUTPUT_PANEL) { - temp = readl(par->df_regs + DF_FP_PM); - - if (!(temp & 0x09)) - writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM); - } - - temp = readl(par->df_regs + DF_MISC); - temp = readl(par->df_regs + DF_DISPLAY_CFG); + if (par->output & OUTPUT_PANEL) + write_fp(par, FP_PM, read_fp(par, FP_PM) | FP_PM_P); } unsigned int lx_framebuffer_size(void) { unsigned int val; + if (!geode_has_vsa2()) { + uint32_t hi, lo; + + /* The number of pages is (PMAX - PMIN)+1 */ + rdmsr(MSR_GLIU_P2D_RO0, lo, hi); + + /* PMAX */ + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20); + /* PMIN */ + val -= (lo & 0x000fffff); + val += 1; + + /* The page size is 4k */ + return (val << 12); + } + /* The frame buffer size is reported by a VSM in VSA II */ /* Virtual Register Class = 0x02 */ /* VG_MEM_SIZE (1MB units) = 0x00 */ - outw(0xFC53, 0xAC1C); - outw(0x0200, 0xAC1C); + outw(VSA_VR_UNLOCK, VSA_VRC_INDEX); + outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX); - val = (unsigned int)(inw(0xAC1E)) & 0xFE; + val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFE; return (val << 20); } @@ -313,7 +368,7 @@ void lx_set_mode(struct fb_info *info) int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; /* Unlock the DC registers */ - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); lx_graphics_disable(info); @@ -321,102 +376,104 @@ void lx_set_mode(struct fb_info *info) /* Set output mode */ - rdmsrl(MSR_LX_DF_GLCONFIG, msrval); - msrval &= ~DF_CONFIG_OUTPUT_MASK; + rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); + msrval &= ~MSR_LX_GLD_MSR_CONFIG_FMT; if (par->output & OUTPUT_PANEL) { - msrval |= DF_OUTPUT_PANEL; + msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_FP; if (par->output & OUTPUT_CRT) - msrval |= DF_SIMULTANEOUS_CRT_AND_FP; + msrval |= MSR_LX_GLD_MSR_CONFIG_FPC; else - msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP; - } else { - msrval |= DF_OUTPUT_CRT; - } + msrval &= ~MSR_LX_GLD_MSR_CONFIG_FPC; + } else + msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_CRT; - wrmsrl(MSR_LX_DF_GLCONFIG, msrval); + wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); /* Clear the various buffers */ /* FIXME: Adjust for panning here */ - writel(0, par->dc_regs + DC_FB_START); - writel(0, par->dc_regs + DC_CB_START); - writel(0, par->dc_regs + DC_CURSOR_START); + write_dc(par, DC_FB_ST_OFFSET, 0); + write_dc(par, DC_CB_ST_OFFSET, 0); + write_dc(par, DC_CURS_ST_OFFSET, 0); /* FIXME: Add support for interlacing */ /* FIXME: Add support for scaling */ - val = readl(par->dc_regs + DC_GENLCK_CTRL); - val &= ~(DC_GC_ALPHA_FLICK_ENABLE | - DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK); + val = read_dc(par, DC_GENLK_CTL); + val &= ~(DC_GENLK_CTL_ALPHA_FLICK_EN | DC_GENLK_CTL_FLICK_EN | + DC_GENLK_CTL_FLICK_SEL_MASK); /* Default scaling params */ - writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE); - writel(0, par->dc_regs + DC_IRQ_FILT_CTL); - writel(val, par->dc_regs + DC_GENLCK_CTRL); + write_dc(par, DC_GFX_SCALE, (0x4000 << 16) | 0x4000); + write_dc(par, DC_IRQ_FILT_CTL, 0); + write_dc(par, DC_GENLK_CTL, val); /* FIXME: Support compression */ if (info->fix.line_length > 4096) - dv = DC_DV_LINE_SIZE_8192; + dv = DC_DV_CTL_DV_LINE_SIZE_8K; else if (info->fix.line_length > 2048) - dv = DC_DV_LINE_SIZE_4096; + dv = DC_DV_CTL_DV_LINE_SIZE_4K; else if (info->fix.line_length > 1024) - dv = DC_DV_LINE_SIZE_2048; + dv = DC_DV_CTL_DV_LINE_SIZE_2K; else - dv = DC_DV_LINE_SIZE_1024; + dv = DC_DV_CTL_DV_LINE_SIZE_1K; max = info->fix.line_length * info->var.yres; max = (max + 0x3FF) & 0xFFFFFC00; - writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP); + write_dc(par, DC_DV_TOP, max | DC_DV_TOP_DV_TOP_EN); - val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK; - writel(val | dv, par->dc_regs + DC_DV_CTL); + val = read_dc(par, DC_DV_CTL) & ~DC_DV_CTL_DV_LINE_SIZE; + write_dc(par, DC_DV_CTL, val | dv); size = info->var.xres * (info->var.bits_per_pixel >> 3); - writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH); - writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE); + write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3); + write_dc(par, DC_LINE_SIZE, (size + 7) >> 3); /* Set default watermark values */ - rdmsrl(MSR_LX_DC_SPARE, msrval); - - msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT | - DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD | - DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM); - msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI; - wrmsrl(MSR_LX_DC_SPARE, msrval); - - gcfg = DC_GCFG_DFLE; /* Display fifo enable */ - gcfg |= 0xB600; /* Set default priority */ - gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */ - - dcfg = DC_DCFG_VDEN; /* Enable video data */ - dcfg |= DC_DCFG_GDEN; /* Enable graphics */ - dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */ - dcfg |= DC_DCFG_TRUP; /* Update timings immediately */ - dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */ - dcfg |= DC_DCFG_VISL; - dcfg |= DC_DCFG_DCEN; /* Always center the display */ + rdmsrl(MSR_LX_SPARE_MSR, msrval); + + msrval &= ~(MSR_LX_SPARE_MSR_DIS_CFIFO_HGO + | MSR_LX_SPARE_MSR_VFIFO_ARB_SEL + | MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M + | MSR_LX_SPARE_MSR_WM_LPEN_OVRD); + msrval |= MSR_LX_SPARE_MSR_DIS_VIFO_WM | + MSR_LX_SPARE_MSR_DIS_INIT_V_PRI; + wrmsrl(MSR_LX_SPARE_MSR, msrval); + + gcfg = DC_GENERAL_CFG_DFLE; /* Display fifo enable */ + gcfg |= (0x6 << DC_GENERAL_CFG_DFHPSL_SHIFT) | /* default priority */ + (0xb << DC_GENERAL_CFG_DFHPEL_SHIFT); + gcfg |= DC_GENERAL_CFG_FDTY; /* Set the frame dirty mode */ + + dcfg = DC_DISPLAY_CFG_VDEN; /* Enable video data */ + dcfg |= DC_DISPLAY_CFG_GDEN; /* Enable graphics */ + dcfg |= DC_DISPLAY_CFG_TGEN; /* Turn on the timing generator */ + dcfg |= DC_DISPLAY_CFG_TRUP; /* Update timings immediately */ + dcfg |= DC_DISPLAY_CFG_PALB; /* Palette bypass in > 8 bpp modes */ + dcfg |= DC_DISPLAY_CFG_VISL; + dcfg |= DC_DISPLAY_CFG_DCEN; /* Always center the display */ /* Set the current BPP mode */ switch (info->var.bits_per_pixel) { case 8: - dcfg |= DC_DCFG_DISP_MODE_8BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP; break; case 16: - dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP; break; case 32: case 24: - dcfg |= DC_DCFG_DISP_MODE_24BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP; break; } @@ -436,35 +493,31 @@ void lx_set_mode(struct fb_info *info) vblankend = vsyncend + info->var.upper_margin; vtotal = vblankend; - writel((hactive - 1) | ((htotal - 1) << 16), - par->dc_regs + DC_H_ACTIVE_TIMING); - writel((hblankstart - 1) | ((hblankend - 1) << 16), - par->dc_regs + DC_H_BLANK_TIMING); - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), - par->dc_regs + DC_H_SYNC_TIMING); - - writel((vactive - 1) | ((vtotal - 1) << 16), - par->dc_regs + DC_V_ACTIVE_TIMING); + write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | ((htotal - 1) << 16)); + write_dc(par, DC_H_BLANK_TIMING, + (hblankstart - 1) | ((hblankend - 1) << 16)); + write_dc(par, DC_H_SYNC_TIMING, + (hsyncstart - 1) | ((hsyncend - 1) << 16)); - writel((vblankstart - 1) | ((vblankend - 1) << 16), - par->dc_regs + DC_V_BLANK_TIMING); + write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | ((vtotal - 1) << 16)); + write_dc(par, DC_V_BLANK_TIMING, + (vblankstart - 1) | ((vblankend - 1) << 16)); + write_dc(par, DC_V_SYNC_TIMING, + (vsyncstart - 1) | ((vsyncend - 1) << 16)); - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), - par->dc_regs + DC_V_SYNC_TIMING); - - writel( (info->var.xres - 1) << 16 | (info->var.yres - 1), - par->dc_regs + DC_FB_ACTIVE); + write_dc(par, DC_FB_ACTIVE, + (info->var.xres - 1) << 16 | (info->var.yres - 1)); /* And re-enable the graphics output */ lx_graphics_enable(info); /* Write the two main configuration registers */ - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); - writel(0, par->dc_regs + DC_ARB_CFG); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_DISPLAY_CFG, dcfg); + write_dc(par, DC_ARB_CFG, 0); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Lock the DC registers */ - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); } void lx_set_palette_reg(struct fb_info *info, unsigned regno, @@ -479,58 +532,310 @@ void lx_set_palette_reg(struct fb_info *info, unsigned regno, val |= (green) & 0x00ff00; val |= (blue >> 8) & 0x0000ff; - writel(regno, par->dc_regs + DC_PAL_ADDRESS); - writel(val, par->dc_regs + DC_PAL_DATA); + write_dc(par, DC_PAL_ADDRESS, regno); + write_dc(par, DC_PAL_DATA, val); } int lx_blank_display(struct fb_info *info, int blank_mode) { struct lxfb_par *par = info->par; u32 dcfg, fp_pm; - int blank, hsync, vsync; + int blank, hsync, vsync, crt; /* CRT power saving modes. */ switch (blank_mode) { case FB_BLANK_UNBLANK: - blank = 0; hsync = 1; vsync = 1; + blank = 0; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_NORMAL: - blank = 1; hsync = 1; vsync = 1; + blank = 1; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_VSYNC_SUSPEND: - blank = 1; hsync = 1; vsync = 0; + blank = 1; hsync = 1; vsync = 0; crt = 1; break; case FB_BLANK_HSYNC_SUSPEND: - blank = 1; hsync = 0; vsync = 1; + blank = 1; hsync = 0; vsync = 1; crt = 1; break; case FB_BLANK_POWERDOWN: - blank = 1; hsync = 0; vsync = 0; + blank = 1; hsync = 0; vsync = 0; crt = 0; break; default: return -EINVAL; } - dcfg = readl(par->df_regs + DF_DISPLAY_CFG); - dcfg &= ~(DF_DCFG_DAC_BL_EN - | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN); + dcfg = read_vp(par, VP_DCFG); + dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_CRT_EN); if (!blank) - dcfg |= DF_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_DAC_BL_EN; if (hsync) - dcfg |= DF_DCFG_HSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN; if (vsync) - dcfg |= DF_DCFG_VSYNC_EN; - writel(dcfg, par->df_regs + DF_DISPLAY_CFG); + dcfg |= VP_DCFG_VSYNC_EN; + if (crt) + dcfg |= VP_DCFG_CRT_EN; + write_vp(par, VP_DCFG, dcfg); /* Power on/off flat panel */ if (par->output & OUTPUT_PANEL) { - fp_pm = readl(par->df_regs + DF_FP_PM); + fp_pm = read_fp(par, FP_PM); if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~DF_FP_PM_P; + fp_pm &= ~FP_PM_P; else - fp_pm |= DF_FP_PM_P; - writel(fp_pm, par->df_regs + DF_FP_PM); + fp_pm |= FP_PM_P; + write_fp(par, FP_PM, fp_pm); } return 0; } + +#ifdef CONFIG_PM + +static void lx_save_regs(struct lxfb_par *par) +{ + uint32_t filt; + int i; + + /* wait for the BLT engine to stop being busy */ + do { + i = read_gp(par, GP_BLT_STATUS); + } while ((i & GP_BLT_STATUS_PB) || !(i & GP_BLT_STATUS_CE)); + + /* save MSRs */ + rdmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel); + rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); + rdmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg); + rdmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare); + + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + + /* save registers */ + memcpy(par->gp, par->gp_regs, sizeof(par->gp)); + memcpy(par->dc, par->dc_regs, sizeof(par->dc)); + memcpy(par->vp, par->vp_regs, sizeof(par->vp)); + memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp)); + + /* save the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + par->pal[i] = read_dc(par, DC_PAL_DATA); + + /* save the horizontal filter coefficients */ + filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + par->hcoeff[i] = read_dc(par, DC_FILT_COEFF1); + par->hcoeff[i + 1] = read_dc(par, DC_FILT_COEFF2); + } + + /* save the vertical filter coefficients */ + filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + par->vcoeff[i] = read_dc(par, DC_FILT_COEFF1); + } + + /* save video coeff ram */ + memcpy(par->vp_coeff, par->vp_regs + VP_VCR, sizeof(par->vp_coeff)); +} + +static void lx_restore_gfx_proc(struct lxfb_par *par) +{ + int i; + + /* a bunch of registers require GP_RASTER_MODE to be set first */ + write_gp(par, GP_RASTER_MODE, par->gp[GP_RASTER_MODE]); + + for (i = 0; i < ARRAY_SIZE(par->gp); i++) { + switch (i) { + case GP_RASTER_MODE: + case GP_VECTOR_MODE: + case GP_BLT_MODE: + case GP_BLT_STATUS: + case GP_HST_SRC: + /* FIXME: restore LUT data */ + case GP_LUT_INDEX: + case GP_LUT_DATA: + /* don't restore these registers */ + break; + + default: + write_gp(par, i, par->gp[i]); + } + } +} + +static void lx_restore_display_ctlr(struct lxfb_par *par) +{ + uint32_t filt; + int i; + + wrmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare); + + for (i = 0; i < ARRAY_SIZE(par->dc); i++) { + switch (i) { + case DC_UNLOCK: + /* unlock the DC; runs first */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + break; + + case DC_GENERAL_CFG: + case DC_DISPLAY_CFG: + /* disable all while restoring */ + write_dc(par, i, 0); + break; + + case DC_DV_CTL: + /* set all ram to dirty */ + write_dc(par, i, par->dc[i] | DC_DV_CTL_CLEAR_DV_RAM); + + case DC_RSVD_1: + case DC_RSVD_2: + case DC_RSVD_3: + case DC_LINE_CNT: + case DC_PAL_ADDRESS: + case DC_PAL_DATA: + case DC_DFIFO_DIAG: + case DC_CFIFO_DIAG: + case DC_FILT_COEFF1: + case DC_FILT_COEFF2: + case DC_RSVD_4: + case DC_RSVD_5: + /* don't restore these registers */ + break; + + default: + write_dc(par, i, par->dc[i]); + } + } + + /* restore the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + write_dc(par, DC_PAL_DATA, par->pal[i]); + + /* restore the horizontal filter coefficients */ + filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + write_dc(par, DC_FILT_COEFF1, par->hcoeff[i]); + write_dc(par, DC_FILT_COEFF2, par->hcoeff[i + 1]); + } + + /* restore the vertical filter coefficients */ + filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + write_dc(par, DC_FILT_COEFF1, par->vcoeff[i]); + } +} + +static void lx_restore_video_proc(struct lxfb_par *par) +{ + int i; + + wrmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg); + wrmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel); + + for (i = 0; i < ARRAY_SIZE(par->vp); i++) { + switch (i) { + case VP_VCFG: + case VP_DCFG: + case VP_PAR: + case VP_PDR: + case VP_CCS: + case VP_RSVD_0: + /* case VP_VDC: */ /* why should this not be restored? */ + case VP_RSVD_1: + case VP_CRC32: + /* don't restore these registers */ + break; + + default: + write_vp(par, i, par->vp[i]); + } + } + + /* restore video coeff ram */ + memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff)); +} + +static void lx_restore_regs(struct lxfb_par *par) +{ + int i; + + lx_set_dotpll((u32) (par->msr.dotpll >> 32)); + lx_restore_gfx_proc(par); + lx_restore_display_ctlr(par); + lx_restore_video_proc(par); + + /* Flat Panel */ + for (i = 0; i < ARRAY_SIZE(par->fp); i++) { + switch (i) { + case FP_PM: + case FP_RSVD_0: + case FP_RSVD_1: + case FP_RSVD_2: + case FP_RSVD_3: + case FP_RSVD_4: + /* don't restore these registers */ + break; + + default: + write_fp(par, i, par->fp[i]); + } + } + + /* control the panel */ + if (par->fp[FP_PM] & FP_PM_P) { + /* power on the panel if not already power{ed,ing} on */ + if (!(read_fp(par, FP_PM) & + (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } else { + /* power down the panel if not already power{ed,ing} down */ + if (!(read_fp(par, FP_PM) & + (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } + + /* turn everything on */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG]); + write_vp(par, VP_DCFG, par->vp[VP_DCFG]); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); + /* do this last; it will enable the FIFO load */ + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); + + /* lock the door behind us */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +int lx_powerdown(struct fb_info *info) +{ + struct lxfb_par *par = info->par; + + if (par->powered_down) + return 0; + + lx_save_regs(par); + lx_graphics_disable(info); + + par->powered_down = 1; + return 0; +} + +int lx_powerup(struct fb_info *info) +{ + struct lxfb_par *par = info->par; + + if (!par->powered_down) + return 0; + + lx_restore_regs(par); + + par->powered_down = 0; + return 0; +} + +#endif diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c new file mode 100644 index 000000000000..9aff32ef8bb6 --- /dev/null +++ b/drivers/video/geode/suspend_gx.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2008 Andres Salomon <dilinger@debian.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. + */ +#include <linux/fb.h> +#include <asm/io.h> +#include <asm/msr.h> +#include <asm/geode.h> +#include <asm/delay.h> + +#include "gxfb.h" + +#ifdef CONFIG_PM + +static void gx_save_regs(struct gxfb_par *par) +{ + int i; + + /* wait for the BLT engine to stop being busy */ + do { + i = read_gp(par, GP_BLT_STATUS); + } while (i & (GP_BLT_STATUS_BLT_PENDING | GP_BLT_STATUS_BLT_BUSY)); + + /* save MSRs */ + rdmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); + rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); + + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + + /* save registers */ + memcpy(par->gp, par->gp_regs, sizeof(par->gp)); + memcpy(par->dc, par->dc_regs, sizeof(par->dc)); + memcpy(par->vp, par->vid_regs, sizeof(par->vp)); + memcpy(par->fp, par->vid_regs + VP_FP_START, sizeof(par->fp)); + + /* save the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + par->pal[i] = read_dc(par, DC_PAL_DATA); +} + +static void gx_set_dotpll(uint32_t dotpll_hi) +{ + uint32_t dotpll_lo; + int i; + + rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); + dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; + dotpll_lo &= ~MSR_GLCP_DOTPLL_BYPASS; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + + /* wait for the PLL to lock */ + for (i = 0; i < 200; i++) { + rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); + if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) + break; + udelay(1); + } + + /* PLL set, unlock */ + dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); +} + +static void gx_restore_gfx_proc(struct gxfb_par *par) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(par->gp); i++) { + switch (i) { + case GP_VECTOR_MODE: + case GP_BLT_MODE: + case GP_BLT_STATUS: + case GP_HST_SRC: + /* don't restore these registers */ + break; + default: + write_gp(par, i, par->gp[i]); + } + } +} + +static void gx_restore_display_ctlr(struct gxfb_par *par) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(par->dc); i++) { + switch (i) { + case DC_UNLOCK: + /* unlock the DC; runs first */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + break; + + case DC_GENERAL_CFG: + /* write without the enables */ + write_dc(par, i, par->dc[i] & ~(DC_GENERAL_CFG_VIDE | + DC_GENERAL_CFG_ICNE | + DC_GENERAL_CFG_CURE | + DC_GENERAL_CFG_DFLE)); + break; + + case DC_DISPLAY_CFG: + /* write without the enables */ + write_dc(par, i, par->dc[i] & ~(DC_DISPLAY_CFG_VDEN | + DC_DISPLAY_CFG_GDEN | + DC_DISPLAY_CFG_TGEN)); + break; + + case DC_RSVD_0: + case DC_RSVD_1: + case DC_RSVD_2: + case DC_RSVD_3: + case DC_RSVD_4: + case DC_LINE_CNT: + case DC_PAL_ADDRESS: + case DC_PAL_DATA: + case DC_DFIFO_DIAG: + case DC_CFIFO_DIAG: + case DC_RSVD_5: + /* don't restore these registers */ + break; + default: + write_dc(par, i, par->dc[i]); + } + } + + /* restore the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + write_dc(par, DC_PAL_DATA, par->pal[i]); +} + +static void gx_restore_video_proc(struct gxfb_par *par) +{ + int i; + + wrmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); + + for (i = 0; i < ARRAY_SIZE(par->vp); i++) { + switch (i) { + case VP_VCFG: + /* don't enable video yet */ + write_vp(par, i, par->vp[i] & ~VP_VCFG_VID_EN); + break; + + case VP_DCFG: + /* don't enable CRT yet */ + write_vp(par, i, par->vp[i] & + ~(VP_DCFG_DAC_BL_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); + break; + + case VP_GAR: + case VP_GDR: + case VP_RSVD_0: + case VP_RSVD_1: + case VP_RSVD_2: + case VP_RSVD_3: + case VP_CRC32: + case VP_AWT: + case VP_VTM: + /* don't restore these registers */ + break; + default: + write_vp(par, i, par->vp[i]); + } + } +} + +static void gx_restore_regs(struct gxfb_par *par) +{ + int i; + + gx_set_dotpll((uint32_t) (par->msr.dotpll >> 32)); + gx_restore_gfx_proc(par); + gx_restore_display_ctlr(par); + gx_restore_video_proc(par); + + /* Flat Panel */ + for (i = 0; i < ARRAY_SIZE(par->fp); i++) { + if (i != FP_PM && i != FP_RSVD_0) + write_fp(par, i, par->fp[i]); + } +} + +static void gx_disable_graphics(struct gxfb_par *par) +{ + /* shut down the engine */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG] & ~VP_VCFG_VID_EN); + write_vp(par, VP_DCFG, par->vp[VP_DCFG] & ~(VP_DCFG_DAC_BL_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); + + /* turn off the flat panel */ + write_fp(par, FP_PM, par->fp[FP_PM] & ~FP_PM_P); + + + /* turn off display */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG] & + ~(DC_GENERAL_CFG_VIDE | DC_GENERAL_CFG_ICNE | + DC_GENERAL_CFG_CURE | DC_GENERAL_CFG_DFLE)); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG] & + ~(DC_DISPLAY_CFG_VDEN | DC_DISPLAY_CFG_GDEN | + DC_DISPLAY_CFG_TGEN)); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +static void gx_enable_graphics(struct gxfb_par *par) +{ + uint32_t fp; + + fp = read_fp(par, FP_PM); + if (par->fp[FP_PM] & FP_PM_P) { + /* power on the panel if not already power{ed,ing} on */ + if (!(fp & (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } else { + /* power down the panel if not already power{ed,ing} down */ + if (!(fp & (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } + + /* turn everything on */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG]); + write_vp(par, VP_DCFG, par->vp[VP_DCFG]); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); + /* do this last; it will enable the FIFO load */ + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); + + /* lock the door behind us */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +int gx_powerdown(struct fb_info *info) +{ + struct gxfb_par *par = info->par; + + if (par->powered_down) + return 0; + + gx_save_regs(par); + gx_disable_graphics(par); + + par->powered_down = 1; + return 0; +} + +int gx_powerup(struct fb_info *info) +{ + struct gxfb_par *par = info->par; + + if (!par->powered_down) + return 0; + + gx_restore_regs(par); + gx_enable_graphics(par); + + par->powered_down = 0; + return 0; +} + +#endif diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index febf09c63492..b8d52a8360db 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -16,9 +16,9 @@ #include <asm/io.h> #include <asm/delay.h> #include <asm/msr.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "video_gx.h" +#include "gxfb.h" /* @@ -117,7 +117,7 @@ static const struct gx_pll_entry gx_pll_table_14MHz[] = { { 4357, 0, 0x0000057D }, /* 229.5000 */ }; -static void gx_set_dclk_frequency(struct fb_info *info) +void gx_set_dclk_frequency(struct fb_info *info) { const struct gx_pll_entry *pll_table; int pll_table_len; @@ -178,110 +178,116 @@ static void gx_set_dclk_frequency(struct fb_info *info) static void gx_configure_tft(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; unsigned long val; unsigned long fp; /* Set up the DF pad select MSR */ - rdmsrl(GX_VP_MSR_PAD_SELECT, val); - val &= ~GX_VP_PAD_SELECT_MASK; - val |= GX_VP_PAD_SELECT_TFT; - wrmsrl(GX_VP_MSR_PAD_SELECT, val); + rdmsrl(MSR_GX_MSR_PADSEL, val); + val &= ~MSR_GX_MSR_PADSEL_MASK; + val |= MSR_GX_MSR_PADSEL_TFT; + wrmsrl(MSR_GX_MSR_PADSEL, val); /* Turn off the panel */ - fp = readl(par->vid_regs + GX_FP_PM); - fp &= ~GX_FP_PM_P; - writel(fp, par->vid_regs + GX_FP_PM); + fp = read_fp(par, FP_PM); + fp &= ~FP_PM_P; + write_fp(par, FP_PM, fp); /* Set timing 1 */ - fp = readl(par->vid_regs + GX_FP_PT1); - fp &= GX_FP_PT1_VSIZE_MASK; - fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT; - writel(fp, par->vid_regs + GX_FP_PT1); + fp = read_fp(par, FP_PT1); + fp &= FP_PT1_VSIZE_MASK; + fp |= info->var.yres << FP_PT1_VSIZE_SHIFT; + write_fp(par, FP_PT1, fp); /* Timing 2 */ /* Set bits that are always on for TFT */ fp = 0x0F100000; - /* Add sync polarity */ + /* Configure sync polarity */ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) - fp |= GX_FP_PT2_VSP; + fp |= FP_PT2_VSP; if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) - fp |= GX_FP_PT2_HSP; + fp |= FP_PT2_HSP; - writel(fp, par->vid_regs + GX_FP_PT2); + write_fp(par, FP_PT2, fp); /* Set the dither control */ - writel(0x70, par->vid_regs + GX_FP_DFC); + write_fp(par, FP_DFC, FP_DFC_NFI); /* Enable the FP data and power (in case the BIOS didn't) */ - fp = readl(par->vid_regs + GX_DCFG); - fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN; - writel(fp, par->vid_regs + GX_DCFG); + fp = read_vp(par, VP_DCFG); + fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN; + write_vp(par, VP_DCFG, fp); /* Unblank the panel */ - fp = readl(par->vid_regs + GX_FP_PM); - fp |= GX_FP_PM_P; - writel(fp, par->vid_regs + GX_FP_PM); + fp = read_fp(par, FP_PM); + fp |= FP_PM_P; + write_fp(par, FP_PM, fp); } -static void gx_configure_display(struct fb_info *info) +void gx_configure_display(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 dcfg, misc; - /* Set up the MISC register */ - - misc = readl(par->vid_regs + GX_MISC); - - /* Power up the DAC */ - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN); - - /* Disable gamma correction */ - misc |= GX_MISC_GAM_EN; - - writel(misc, par->vid_regs + GX_MISC); - /* Write the display configuration */ - dcfg = readl(par->vid_regs + GX_DCFG); + dcfg = read_vp(par, VP_DCFG); /* Disable hsync and vsync */ - dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); - writel(dcfg, par->vid_regs + GX_DCFG); + dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN); + write_vp(par, VP_DCFG, dcfg); /* Clear bits from existing mode. */ - dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK - | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL - | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); + dcfg &= ~(VP_DCFG_CRT_SYNC_SKW + | VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL + | VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN); /* Set default sync skew. */ - dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT; + dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT; /* Enable hsync and vsync. */ - dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN; - /* Sync polarities. */ - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - dcfg |= GX_DCFG_CRT_HSYNC_POL; - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - dcfg |= GX_DCFG_CRT_VSYNC_POL; + misc = read_vp(par, VP_MISC); + + /* Disable gamma correction */ + misc |= VP_MISC_GAM_EN; + + if (par->enable_crt) { + + /* Power up the CRT DACs */ + misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN); + write_vp(par, VP_MISC, misc); + + /* Only change the sync polarities if we are running + * in CRT mode. The FP polarities will be handled in + * gxfb_configure_tft */ + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + dcfg |= VP_DCFG_CRT_HSYNC_POL; + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + dcfg |= VP_DCFG_CRT_VSYNC_POL; + } else { + /* Power down the CRT DACs if in FP mode */ + misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN); + write_vp(par, VP_MISC, misc); + } /* Enable the display logic */ /* Set up the DACS to blank normally */ - dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN; /* Enable the external DAC VREF? */ - writel(dcfg, par->vid_regs + GX_DCFG); + write_vp(par, VP_DCFG, dcfg); /* Set up the flat panel (if it is enabled) */ @@ -289,59 +295,55 @@ static void gx_configure_display(struct fb_info *info) gx_configure_tft(info); } -static int gx_blank_display(struct fb_info *info, int blank_mode) +int gx_blank_display(struct fb_info *info, int blank_mode) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 dcfg, fp_pm; - int blank, hsync, vsync; + int blank, hsync, vsync, crt; /* CRT power saving modes. */ switch (blank_mode) { case FB_BLANK_UNBLANK: - blank = 0; hsync = 1; vsync = 1; + blank = 0; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_NORMAL: - blank = 1; hsync = 1; vsync = 1; + blank = 1; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_VSYNC_SUSPEND: - blank = 1; hsync = 1; vsync = 0; + blank = 1; hsync = 1; vsync = 0; crt = 1; break; case FB_BLANK_HSYNC_SUSPEND: - blank = 1; hsync = 0; vsync = 1; + blank = 1; hsync = 0; vsync = 1; crt = 1; break; case FB_BLANK_POWERDOWN: - blank = 1; hsync = 0; vsync = 0; + blank = 1; hsync = 0; vsync = 0; crt = 0; break; default: return -EINVAL; } - dcfg = readl(par->vid_regs + GX_DCFG); - dcfg &= ~(GX_DCFG_DAC_BL_EN - | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN); + dcfg = read_vp(par, VP_DCFG); + dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_CRT_EN); if (!blank) - dcfg |= GX_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_DAC_BL_EN; if (hsync) - dcfg |= GX_DCFG_HSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN; if (vsync) - dcfg |= GX_DCFG_VSYNC_EN; - writel(dcfg, par->vid_regs + GX_DCFG); + dcfg |= VP_DCFG_VSYNC_EN; + if (crt) + dcfg |= VP_DCFG_CRT_EN; + write_vp(par, VP_DCFG, dcfg); /* Power on/off flat panel. */ if (par->enable_crt == 0) { - fp_pm = readl(par->vid_regs + GX_FP_PM); + fp_pm = read_fp(par, FP_PM); if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~GX_FP_PM_P; + fp_pm &= ~FP_PM_P; else - fp_pm |= GX_FP_PM_P; - writel(fp_pm, par->vid_regs + GX_FP_PM); + fp_pm |= FP_PM_P; + write_fp(par, FP_PM, fp_pm); } return 0; } - -struct geode_vid_ops gx_vid_ops = { - .set_dclk = gx_set_dclk_frequency, - .configure_display = gx_configure_display, - .blank_display = gx_blank_display, -}; diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h deleted file mode 100644 index ce28d8f382dc..000000000000 --- a/drivers/video/geode/video_gx.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Geode GX video device - * - * Copyright (C) 2006 Arcom Control Systems Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef __VIDEO_GX_H__ -#define __VIDEO_GX_H__ - -extern struct geode_vid_ops gx_vid_ops; - -/* GX Flatpanel control MSR */ -#define GX_VP_MSR_PAD_SELECT 0xC0002011 -#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF -#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF - -/* Geode GX video processor registers */ - -#define GX_DCFG 0x0008 -# define GX_DCFG_CRT_EN 0x00000001 -# define GX_DCFG_HSYNC_EN 0x00000002 -# define GX_DCFG_VSYNC_EN 0x00000004 -# define GX_DCFG_DAC_BL_EN 0x00000008 -# define GX_DCFG_FP_PWR_EN 0x00000040 -# define GX_DCFG_FP_DATA_EN 0x00000080 -# define GX_DCFG_CRT_HSYNC_POL 0x00000100 -# define GX_DCFG_CRT_VSYNC_POL 0x00000200 -# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000 -# define GX_DCFG_CRT_SYNC_SKW_DFLT 0x00010000 -# define GX_DCFG_VG_CK 0x00100000 -# define GX_DCFG_GV_GAM 0x00200000 -# define GX_DCFG_DAC_VREF 0x04000000 - -/* Geode GX MISC video configuration */ - -#define GX_MISC 0x50 -#define GX_MISC_GAM_EN 0x00000001 -#define GX_MISC_DAC_PWRDN 0x00000400 -#define GX_MISC_A_PWRDN 0x00000800 - -/* Geode GX flat panel display control registers */ - -#define GX_FP_PT1 0x0400 -#define GX_FP_PT1_VSIZE_MASK 0x7FF0000 -#define GX_FP_PT1_VSIZE_SHIFT 16 - -#define GX_FP_PT2 0x408 -#define GX_FP_PT2_VSP (1 << 23) -#define GX_FP_PT2_HSP (1 << 22) - -#define GX_FP_PM 0x410 -# define GX_FP_PM_P 0x01000000 - -#define GX_FP_DFC 0x418 - -/* Geode GX clock control MSRs */ - -#define MSR_GLCP_SYS_RSTPLL 0x4c000014 -# define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull) -# define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull) -# define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull) - -#define MSR_GLCP_DOTPLL 0x4c000015 -# define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull) -# define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull) -# define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull) - -#endif /* !__VIDEO_GX_H__ */ diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index e92337bef50d..564557792bed 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -238,7 +238,7 @@ static int calc_pll(int period_ps, struct gxt4500_par *par) for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) { for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) { postdiv = pdiv1 * pdiv2; - pll_period = (period_ps + postdiv - 1) / postdiv; + pll_period = DIV_ROUND_UP(period_ps, postdiv); /* keep pll in range 350..600 MHz */ if (pll_period < 1666 || pll_period > 2857) continue; diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c index 94e0df8a6f60..0b4bffbe67c8 100644 --- a/drivers/video/hecubafb.c +++ b/drivers/video/hecubafb.c @@ -1,5 +1,5 @@ /* - * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller + * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller * * Copyright (C) 2006, Jaya Kumar * This work was sponsored by CIS(M) Sdn Bhd @@ -17,18 +17,13 @@ * values. There are other commands that the display is capable of, * beyond the 5 used here but they are more complex. * - * This driver is written to be used with the Hecuba display controller - * board, and tested with the EInk 800x600 display in 1 bit mode. - * The interface between Hecuba and the host is TTL based GPIO. The - * GPIO requirements are 8 writable data lines and 6 lines for control. - * Only 4 of the controls are actually used here but 6 for future use. - * The driver requires the IO addresses for data and control GPIO at - * load time. It is also possible to use this display with a standard - * PC parallel port. + * This driver is written to be used with the Hecuba display architecture. + * The actual display chip is called Apollo and the interface electronics + * it needs is called Hecuba. * - * General notes: - * - User must set hecubafb_enable=1 to enable it - * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * It is intended to be architecture independent. A board specific driver + * must be used to perform all the physical IO interactions. An example + * is provided as n411.c * */ @@ -47,34 +42,12 @@ #include <linux/list.h> #include <linux/uaccess.h> -/* Apollo controller specific defines */ -#define APOLLO_START_NEW_IMG 0xA0 -#define APOLLO_STOP_IMG_DATA 0xA1 -#define APOLLO_DISPLAY_IMG 0xA2 -#define APOLLO_ERASE_DISPLAY 0xA3 -#define APOLLO_INIT_DISPLAY 0xA4 - -/* Hecuba interface specific defines */ -/* WUP is inverted, CD is inverted, DS is inverted */ -#define HCB_NWUP_BIT 0x01 -#define HCB_NDS_BIT 0x02 -#define HCB_RW_BIT 0x04 -#define HCB_NCD_BIT 0x08 -#define HCB_ACK_BIT 0x80 +#include <video/hecubafb.h> /* Display specific information */ #define DPY_W 600 #define DPY_H 800 -struct hecubafb_par { - unsigned long dio_addr; - unsigned long cio_addr; - unsigned long c2io_addr; - unsigned char ctl; - struct fb_info *info; - unsigned int irq; -}; - static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { .id = "hecubafb", .type = FB_TYPE_PACKED_PIXELS, @@ -82,6 +55,7 @@ static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { .xpanstep = 0, .ypanstep = 0, .ywrapstep = 0, + .line_length = DPY_W, .accel = FB_ACCEL_NONE, }; @@ -94,136 +68,51 @@ static struct fb_var_screeninfo hecubafb_var __devinitdata = { .nonstd = 1, }; -static unsigned long dio_addr; -static unsigned long cio_addr; -static unsigned long c2io_addr; -static unsigned long splashval; -static unsigned int nosplash; -static unsigned int hecubafb_enable; -static unsigned int irq; - -static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq); - -static void hcb_set_ctl(struct hecubafb_par *par) -{ - outb(par->ctl, par->cio_addr); -} - -static unsigned char hcb_get_ctl(struct hecubafb_par *par) -{ - return inb(par->c2io_addr); -} - -static void hcb_set_data(struct hecubafb_par *par, unsigned char value) -{ - outb(value, par->dio_addr); -} - -static int __devinit apollo_init_control(struct hecubafb_par *par) -{ - unsigned char ctl; - /* for init, we want the following setup to be set: - WUP = lo - ACK = hi - DS = hi - RW = hi - CD = lo - */ - - /* write WUP to lo, DS to hi, RW to hi, CD to lo */ - par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ; - par->ctl &= ~HCB_NDS_BIT; - hcb_set_ctl(par); - - /* check ACK is not lo */ - ctl = hcb_get_ctl(par); - if ((ctl & HCB_ACK_BIT)) { - printk(KERN_ERR "Fail because ACK is already low\n"); - return -ENXIO; - } - - return 0; -} - -static void hcb_wait_for_ack(struct hecubafb_par *par) -{ - - int timeout; - unsigned char ctl; - - timeout=500; - do { - ctl = hcb_get_ctl(par); - if ((ctl & HCB_ACK_BIT)) - return; - udelay(1); - } while (timeout--); - printk(KERN_ERR "timed out waiting for ack\n"); -} - -static void hcb_wait_for_ack_clear(struct hecubafb_par *par) -{ - - int timeout; - unsigned char ctl; - - timeout=500; - do { - ctl = hcb_get_ctl(par); - if (!(ctl & HCB_ACK_BIT)) - return; - udelay(1); - } while (timeout--); - printk(KERN_ERR "timed out waiting for clear\n"); -} +/* main hecubafb functions */ static void apollo_send_data(struct hecubafb_par *par, unsigned char data) { /* set data */ - hcb_set_data(par, data); + par->board->set_data(par, data); /* set DS low */ - par->ctl |= HCB_NDS_BIT; - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_DS_BIT, 0); - hcb_wait_for_ack(par); + /* wait for ack */ + par->board->wait_for_ack(par, 0); /* set DS hi */ - par->ctl &= ~(HCB_NDS_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_DS_BIT, 1); - hcb_wait_for_ack_clear(par); + /* wait for ack to clear */ + par->board->wait_for_ack(par, 1); } static void apollo_send_command(struct hecubafb_par *par, unsigned char data) { /* command so set CD to high */ - par->ctl &= ~(HCB_NCD_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_CD_BIT, 1); /* actually strobe with command */ apollo_send_data(par, data); /* clear CD back to low */ - par->ctl |= (HCB_NCD_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_CD_BIT, 0); } -/* main hecubafb functions */ - static void hecubafb_dpy_update(struct hecubafb_par *par) { int i; unsigned char *buf = (unsigned char __force *)par->info->screen_base; - apollo_send_command(par, 0xA0); + apollo_send_command(par, APOLLO_START_NEW_IMG); for (i=0; i < (DPY_W*DPY_H/8); i++) { apollo_send_data(par, *(buf++)); } - apollo_send_command(par, 0xA1); - apollo_send_command(par, 0xA2); + apollo_send_command(par, APOLLO_STOP_IMG_DATA); + apollo_send_command(par, APOLLO_DISPLAY_IMG); } /* this is called back from the deferred io workqueue */ @@ -270,41 +159,43 @@ static void hecubafb_imageblit(struct fb_info *info, static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { - unsigned long p; - int err=-EINVAL; - struct hecubafb_par *par; - unsigned int xres; - unsigned int fbmemlength; + struct hecubafb_par *par = info->par; + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; - p = *ppos; - par = info->par; - xres = info->var.xres; - fbmemlength = (xres * info->var.yres)/8; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; - if (p > fbmemlength) - return -ENOSPC; + total_size = info->fix.smem_len; - err = 0; - if ((count + p) > fbmemlength) { - count = fbmemlength - p; - err = -ENOSPC; + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; } - if (count) { - char *base_addr; + if (count + p > total_size) { + if (!err) + err = -ENOSPC; - base_addr = (char __force *)info->screen_base; - count -= copy_from_user(base_addr + p, buf, count); - *ppos += count; - err = -EFAULT; + count = total_size - p; } - hecubafb_dpy_update(par); + dst = (void __force *) (info->screen_base + p); + + if (copy_from_user(dst, buf, count)) + err = -EFAULT; - if (count) - return count; + if (!err) + *ppos += count; - return err; + hecubafb_dpy_update(par); + + return (err) ? err : count; } static struct fb_ops hecubafb_ops = { @@ -324,11 +215,21 @@ static struct fb_deferred_io hecubafb_defio = { static int __devinit hecubafb_probe(struct platform_device *dev) { struct fb_info *info; + struct hecuba_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; struct hecubafb_par *par; + /* pick up board specific routines */ + board = dev->dev.platform_data; + if (!board) + return -EINVAL; + + /* try to count device specific driver, if can't, platform recalls */ + if (!try_module_get(board->owner)) + return -ENODEV; + videomemorysize = (DPY_W*DPY_H)/8; if (!(videomemory = vmalloc(videomemorysize))) @@ -338,9 +239,9 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); if (!info) - goto err; + goto err_fballoc; - info->screen_base = (char __iomem *) videomemory; + info->screen_base = (char __force __iomem *)videomemory; info->fbops = &hecubafb_ops; info->var = hecubafb_var; @@ -348,14 +249,10 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info->fix.smem_len = videomemorysize; par = info->par; par->info = info; + par->board = board; + par->send_command = apollo_send_command; + par->send_data = apollo_send_data; - if (!dio_addr || !cio_addr || !c2io_addr) { - printk(KERN_WARNING "no IO addresses supplied\n"); - goto err1; - } - par->dio_addr = dio_addr; - par->cio_addr = cio_addr; - par->c2io_addr = c2io_addr; info->flags = FBINFO_FLAG_DEFAULT; info->fbdefio = &hecubafb_defio; @@ -363,7 +260,7 @@ static int __devinit hecubafb_probe(struct platform_device *dev) retval = register_framebuffer(info); if (retval < 0) - goto err1; + goto err_fbreg; platform_set_drvdata(dev, info); printk(KERN_INFO @@ -371,25 +268,16 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info->node, videomemorysize >> 10); /* this inits the dpy */ - apollo_init_control(par); - - apollo_send_command(par, APOLLO_INIT_DISPLAY); - apollo_send_data(par, 0x81); - - /* have to wait while display resets */ - udelay(1000); - - /* if we were told to splash the screen, we just clear it */ - if (!nosplash) { - apollo_send_command(par, APOLLO_ERASE_DISPLAY); - apollo_send_data(par, splashval); - } + retval = par->board->init(par); + if (retval < 0) + goto err_fbreg; return 0; -err1: +err_fbreg: framebuffer_release(info); -err: +err_fballoc: vfree(videomemory); + module_put(board->owner); return retval; } @@ -398,9 +286,13 @@ static int __devexit hecubafb_remove(struct platform_device *dev) struct fb_info *info = platform_get_drvdata(dev); if (info) { + struct hecubafb_par *par = info->par; fb_deferred_io_cleanup(info); unregister_framebuffer(info); vfree((void __force *)info->screen_base); + if (par->board->remove) + par->board->remove(par); + module_put(par->board->owner); framebuffer_release(info); } return 0; @@ -410,62 +302,24 @@ static struct platform_driver hecubafb_driver = { .probe = hecubafb_probe, .remove = hecubafb_remove, .driver = { + .owner = THIS_MODULE, .name = "hecubafb", }, }; -static struct platform_device *hecubafb_device; - static int __init hecubafb_init(void) { - int ret; - - if (!hecubafb_enable) { - printk(KERN_ERR "Use hecubafb_enable to enable the device\n"); - return -ENXIO; - } - - ret = platform_driver_register(&hecubafb_driver); - if (!ret) { - hecubafb_device = platform_device_alloc("hecubafb", 0); - if (hecubafb_device) - ret = platform_device_add(hecubafb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(hecubafb_device); - platform_driver_unregister(&hecubafb_driver); - } - } - return ret; - + return platform_driver_register(&hecubafb_driver); } static void __exit hecubafb_exit(void) { - platform_device_unregister(hecubafb_device); platform_driver_unregister(&hecubafb_driver); } -module_param(nosplash, uint, 0); -MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); -module_param(hecubafb_enable, uint, 0); -MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board"); -module_param(dio_addr, ulong, 0); -MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); -module_param(cio_addr, ulong, 0); -MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); -module_param(c2io_addr, ulong, 0); -MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); -module_param(splashval, ulong, 0); -MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); -module_param(irq, uint, 0); -MODULE_PARM_DESC(irq, "IRQ for the Hecuba board"); - module_init(hecubafb_init); module_exit(hecubafb_exit); -MODULE_DESCRIPTION("fbdev driver for Hecuba board"); +MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller"); MODULE_AUTHOR("Jaya Kumar"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 3ab91bf21576..15d50b9906ce 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1151,8 +1151,10 @@ imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc par->cmap_regs[TVPCRDAT] = 0xff; eieio(); } par->cmap_regs[TVPCADRW] = 0x00; eieio(); - for (x = 0; x < 12; x++) - par->cmap_regs[TVPCDATA] = fgc; eieio(); + for (x = 0; x < 12; x++) { + par->cmap_regs[TVPCDATA] = fgc; + eieio(); + } } return 1; } @@ -1476,7 +1478,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dp = pci_device_to_OF_node(pdev); if(dp) - printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name); + printk(KERN_INFO "%s: OF name %s\n",__func__, dp->name); else printk(KERN_ERR "imsttfb: no OF node for pci device\n"); #endif /* CONFIG_PPC_OF */ diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 11609552a387..94e4d3ac1a05 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -415,7 +415,7 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) static int imxfb_suspend(struct platform_device *dev, pm_message_t state) { struct imxfb_info *fbi = platform_get_drvdata(dev); - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); imxfb_disable_controller(fbi); return 0; @@ -424,7 +424,7 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state) static int imxfb_resume(struct platform_device *dev) { struct imxfb_info *fbi = platform_get_drvdata(dev); - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); imxfb_enable_controller(fbi); return 0; @@ -440,7 +440,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) struct fb_info *info = dev_get_drvdata(dev); struct imxfb_info *fbi = info->par; - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL); if (!info->pseudo_palette) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 836796177942..3325fbd68ab3 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -12,9 +12,9 @@ #endif /*** Version/name ***/ -#define INTELFB_VERSION "0.9.4" +#define INTELFB_VERSION "0.9.5" #define INTELFB_MODULE_NAME "intelfb" -#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM" /*** Debug/feature defines ***/ @@ -58,6 +58,8 @@ #define PCI_DEVICE_ID_INTEL_915GM 0x2592 #define PCI_DEVICE_ID_INTEL_945G 0x2772 #define PCI_DEVICE_ID_INTEL_945GM 0x27A2 +#define PCI_DEVICE_ID_INTEL_965G 0x29A2 +#define PCI_DEVICE_ID_INTEL_965GM 0x2A02 /* Size of MMIO region */ #define INTEL_REG_SIZE 0x80000 @@ -158,6 +160,8 @@ enum intel_chips { INTEL_915GM, INTEL_945G, INTEL_945GM, + INTEL_965G, + INTEL_965GM, }; struct intelfb_hwstate { @@ -358,7 +362,9 @@ struct intelfb_info { #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \ ((dinfo)->chipset == INTEL_915GM) || \ ((dinfo)->chipset == INTEL_945G) || \ - ((dinfo)->chipset==INTEL_945GM)) + ((dinfo)->chipset == INTEL_945GM) || \ + ((dinfo)->chipset == INTEL_965G) || \ + ((dinfo)->chipset == INTEL_965GM)) #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 94c08bb5acf1..ca95f09d8b43 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -169,6 +169,8 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) /* has some LVDS + tv-out */ case INTEL_945G: case INTEL_945GM: + case INTEL_965G: + case INTEL_965GM: /* SDVO ports have a single control bus - 2 devices */ dinfo->output[i].type = INTELFB_OUTPUT_SDVO; intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 481d58f7535d..e44303f9bc52 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -2,7 +2,7 @@ * intelfb * * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ - * 945G/945GM integrated graphics chips. + * 945G/945GM/965G/965GM integrated graphics chips. * * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> * 2004 Sylvain Meyer @@ -99,6 +99,9 @@ * Add vram option to reserve more memory than stolen by BIOS * Fix intelfbhw_pan_display typo * Add __initdata annotations + * + * 04/2008 - Version 0.9.5 + * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>) */ #include <linux/module.h> @@ -180,6 +183,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM }, { 0, } }; @@ -549,7 +554,10 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || (ent->device == PCI_DEVICE_ID_INTEL_915GM) || (ent->device == PCI_DEVICE_ID_INTEL_945G) || - (ent->device == PCI_DEVICE_ID_INTEL_945GM)) { + (ent->device == PCI_DEVICE_ID_INTEL_945GM) || + (ent->device == PCI_DEVICE_ID_INTEL_965G) || + (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { + aperture_bar = 2; mmio_bar = 0; } diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index fa1fff553565..8e6d6a4db0ad 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -143,6 +143,18 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) dinfo->mobile = 1; dinfo->pll_index = PLLS_I9xx; return 0; + case PCI_DEVICE_ID_INTEL_965G: + dinfo->name = "Intel(R) 965G"; + dinfo->chipset = INTEL_965G; + dinfo->mobile = 0; + dinfo->pll_index = PLLS_I9xx; + return 0; + case PCI_DEVICE_ID_INTEL_965GM: + dinfo->name = "Intel(R) 965GM"; + dinfo->chipset = INTEL_965GM; + dinfo->mobile = 1; + dinfo->pll_index = PLLS_I9xx; + return 0; default: return 1; } @@ -174,7 +186,9 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, case PCI_DEVICE_ID_INTEL_915GM: case PCI_DEVICE_ID_INTEL_945G: case PCI_DEVICE_ID_INTEL_945GM: - /* 915 and 945 chipsets support a 256MB aperture. + case PCI_DEVICE_ID_INTEL_965G: + case PCI_DEVICE_ID_INTEL_965GM: + /* 915, 945 and 965 chipsets support a 256MB aperture. Aperture size is determined by inspected the base address of the aperture. */ if (pci_resource_start(pdev, 2) & 0x08000000) diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 45b9a5d55dec..f3160fc29795 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -614,7 +614,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: leo at %lx:%lx\n", + printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index c4b570b4a4df..0ce3b0a89798 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -37,7 +37,7 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi unsigned int fvco; unsigned int p; - DBG(__FUNCTION__) + DBG(__func__) /* only for devices older than G450 */ @@ -83,7 +83,7 @@ static const unsigned char MGA1064_DAC[] = { static void DAC1064_setpclk(WPMINFO unsigned long fout) { unsigned int m, n, p; - DBG(__FUNCTION__) + DBG(__func__) DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); ACCESS_FBINFO(hw).DACclk[0] = m; @@ -95,7 +95,7 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { u_int32_t mx; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(devflags.noinit)) { /* read MCLK and give up... */ @@ -338,7 +338,7 @@ void DAC1064_global_restore(WPMINFO2) { static int DAC1064_init_1(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { @@ -374,7 +374,7 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m) { static int DAC1064_init_2(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */ int i; @@ -418,7 +418,7 @@ static void DAC1064_restore_1(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -448,7 +448,7 @@ static void DAC1064_restore_2(WPMINFO2) { unsigned int i; #endif - DBG(__FUNCTION__) + DBG(__func__) #ifdef DEBUG dprintk(KERN_DEBUG "DAC1064regs "); @@ -521,7 +521,7 @@ static struct matrox_altout g450out = { static int MGA1064_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (DAC1064_init_1(PMINFO m)) return 1; if (matroxfb_vgaHWinit(PMINFO m)) return 1; @@ -543,7 +543,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m) { static int MGAG100_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (DAC1064_init_1(PMINFO m)) return 1; hw->MXoptionReg &= ~0x2000; @@ -565,7 +565,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m) { #ifdef CONFIG_FB_MATROX_MYSTIQUE static void MGA1064_ramdac_init(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; @@ -594,7 +594,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { int selClk; int clk; - DBG(__FUNCTION__) + DBG(__func__) outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | M1064_XPIXCLKCTRL_PLL_UP); @@ -636,7 +636,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { static void MGAG100_setPixClock(CPMINFO int flags, int freq) { unsigned int m, n, p; - DBG(__FUNCTION__) + DBG(__func__) DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); MGAG100_progPixClock(PMINFO flags, m, n, p); @@ -650,7 +650,7 @@ static int MGA1064_preinit(WPMINFO2) { 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ ACCESS_FBINFO(capable.text) = 1; @@ -683,7 +683,7 @@ static int MGA1064_preinit(WPMINFO2) { static void MGA1064_reset(WPMINFO2) { - DBG(__FUNCTION__); + DBG(__func__); MGA1064_ramdac_init(PMINFO2); } @@ -819,7 +819,7 @@ static int MGAG100_preinit(WPMINFO2) { u_int32_t q; #endif - DBG(__FUNCTION__) + DBG(__func__) /* there are some instabilities if in_div > 19 && vco < 61000 */ if (ACCESS_FBINFO(devflags.g450dac)) { @@ -956,7 +956,7 @@ static void MGAG100_reset(WPMINFO2) { u_int8_t b; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) { #ifdef G100_BROKEN_IBM_82351 @@ -1015,7 +1015,7 @@ static void MGA1064_restore(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -1041,7 +1041,7 @@ static void MGAG100_restore(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index 9445cdb759b1..13524821e242 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -283,7 +283,7 @@ static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* i unsigned int fvco; unsigned int lin, lfeed, lpost; - DBG(__FUNCTION__) + DBG(__func__) fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); fvco >>= (*post = lpost); @@ -297,7 +297,7 @@ static int Ti3026_setpclk(WPMINFO int clk) { unsigned int pixfeed, pixin, pixpost; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); @@ -365,7 +365,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m) { u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { @@ -440,7 +440,7 @@ static void ti3026_setMCLK(WPMINFO int fout){ unsigned int rfhcnt, mclk_ctl; int tmout; - DBG(__FUNCTION__) + DBG(__func__) f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); @@ -534,7 +534,7 @@ static void ti3026_setMCLK(WPMINFO int fout){ static void ti3026_ramdac_init(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; ACCESS_FBINFO(features.pll.ref_freq) = 114545; @@ -554,7 +554,7 @@ static void Ti3026_restore(WPMINFO2) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) #ifdef DEBUG dprintk(KERN_INFO "EXTVGA regs: "); @@ -662,7 +662,7 @@ static void Ti3026_restore(WPMINFO2) { static void Ti3026_reset(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) ti3026_ramdac_init(PMINFO2); } @@ -680,7 +680,7 @@ static int Ti3026_preinit(WPMINFO2) { 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) ACCESS_FBINFO(millenium) = 1; ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index 3660d2673bdc..9c3aeee1cc4f 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -113,7 +113,7 @@ void matrox_cfbX_init(WPMINFO2) { u_int32_t mopmode; int accel; - DBG(__FUNCTION__) + DBG(__func__) mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual; @@ -199,7 +199,7 @@ static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx int start, end; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -235,7 +235,7 @@ static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, in int start, end; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -287,7 +287,7 @@ static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int he int width) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -315,7 +315,7 @@ static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int heigh int whattodo; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -388,7 +388,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, int easy; CRITFLAGS - DBG_HEAVY(__FUNCTION__); + DBG_HEAVY(__func__); step = (width + 7) >> 3; charcell = height * step; @@ -469,7 +469,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) { MINFO_FROM_INFO(info); - DBG_HEAVY(__FUNCTION__); + DBG_HEAVY(__func__); if (image->depth == 1) { u_int32_t fgx, bgx; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index b25972ac6eeb..54e82f35353d 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -312,7 +312,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) return; @@ -392,7 +392,7 @@ static int matroxfb_open(struct fb_info *info, int user) { MINFO_FROM_INFO(info); - DBG_LOOP(__FUNCTION__) + DBG_LOOP(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -408,7 +408,7 @@ static int matroxfb_release(struct fb_info *info, int user) { MINFO_FROM_INFO(info); - DBG_LOOP(__FUNCTION__) + DBG_LOOP(__func__) if (user) { if (0 == --ACCESS_FBINFO(userusecount)) { @@ -425,7 +425,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) { MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) matrox_pan_var(PMINFO var); return 0; @@ -434,7 +434,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, static int matroxfb_get_final_bppShift(CPMINFO int bpp) { int bppshft2; - DBG(__FUNCTION__) + DBG(__func__) bppshft2 = bpp; if (!bppshft2) { @@ -451,7 +451,7 @@ static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { int over; int rounding; - DBG(__FUNCTION__) + DBG(__func__) switch (bpp) { case 0: return xres; @@ -482,7 +482,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { const int* width; int xres_new; - DBG(__FUNCTION__) + DBG(__func__) if (!bpp) return xres; @@ -504,7 +504,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { - DBG(__FUNCTION__) + DBG(__func__) switch (var->bits_per_pixel) { case 4: @@ -548,7 +548,7 @@ static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visua unsigned int vramlen; unsigned int memlen; - DBG(__FUNCTION__) + DBG(__func__) switch (bpp) { case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; @@ -648,7 +648,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); #endif - DBG(__FUNCTION__) + DBG(__func__) /* * Set a single color register. The values supplied are @@ -707,7 +707,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, static void matroxfb_init_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG(__FUNCTION__) + DBG(__func__) strcpy(fix->id,"MATROX"); @@ -722,7 +722,7 @@ static void matroxfb_init_fix(WPMINFO2) static void matroxfb_update_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG(__FUNCTION__) + DBG(__func__) fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); @@ -753,7 +753,7 @@ static int matroxfb_set_par(struct fb_info *info) struct fb_var_screeninfo *var; MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -876,7 +876,7 @@ static int matroxfb_ioctl(struct fb_info *info, void __user *argp = (void __user *)arg; MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -1175,7 +1175,7 @@ static int matroxfb_blank(int blank, struct fb_info *info) CRITFLAGS MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) return 1; @@ -1287,7 +1287,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi unsigned char bytes[32]; unsigned char* tmp; - DBG(__FUNCTION__) + DBG(__func__) vm = ACCESS_FBINFO(video.vbase); maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ @@ -1593,7 +1593,7 @@ static int initMatrox2(WPMINFO struct board* b){ { }, }; - DBG(__FUNCTION__) + DBG(__func__) /* set default values... */ vesafb_defined.accel_flags = FB_ACCELF_TEXT; @@ -2006,7 +2006,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm #ifndef CONFIG_FB_MATROX_MULTIHEAD static int registered = 0; #endif - DBG(__FUNCTION__) + DBG(__func__) svid = pdev->subsystem_vendor; sid = pdev->subsystem_device; @@ -2301,7 +2301,7 @@ static void __exit matrox_done(void) { static int __init matroxfb_setup(char *options) { char *this_opt; - DBG(__FUNCTION__) + DBG(__func__) if (!options || !*options) return 0; @@ -2444,7 +2444,7 @@ static int __init matroxfb_init(void) char *option = NULL; int err = 0; - DBG(__FUNCTION__) + DBG(__func__) if (fb_get_options("matroxfb", &option)) return -ENODEV; @@ -2556,7 +2556,7 @@ MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit defau int __init init_module(void){ - DBG(__FUNCTION__) + DBG(__func__) if (disabled) return -ENXIO; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index a6ab5b6a58d0..7ac4c5f6145d 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -420,7 +420,7 @@ static int matroxfb_dh_ioctl(struct fb_info *info, #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); - DBG(__FUNCTION__) + DBG(__func__) switch (cmd) { case FBIOGET_VBLANK: diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 0cd58f84fb46..89da27bd5c49 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -220,7 +220,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, unsigned int scrlen; unsigned int fmax; - DBG(__FUNCTION__) + DBG(__func__) scrlen = htotal * (vtotal - 1); fwant = htotal * vtotal; diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index ab7fb50bc1de..5b5f072fc1a8 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -90,13 +90,13 @@ #include <linux/matroxfb.h> void matroxfb_DAC_out(CPMINFO int reg, int val) { - DBG_REG(__FUNCTION__) + DBG_REG(__func__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); } int matroxfb_DAC_in(CPMINFO int reg) { - DBG_REG(__FUNCTION__) + DBG_REG(__func__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); } @@ -104,7 +104,7 @@ int matroxfb_DAC_in(CPMINFO int reg) { void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { unsigned int pixclock = var->pixclock; - DBG(__FUNCTION__) + DBG(__func__) if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ mt->pixclock = 1000000000 / pixclock; @@ -131,7 +131,7 @@ int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int f unsigned int fwant; unsigned int p; - DBG(__FUNCTION__) + DBG(__func__) fwant = freq; @@ -192,7 +192,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { int i; struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) hw->SEQ[0] = 0x00; hw->SEQ[1] = 0x01; /* or 0x09 */ @@ -336,7 +336,7 @@ void matroxfb_vgaHWrestore(WPMINFO2) { struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); dprintk(KERN_INFO "SEQ regs: "); @@ -522,8 +522,6 @@ static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) { #endif } -#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x)))) -#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x)))) static int parse_pins1(WPMINFO const struct matrox_bios* bd) { unsigned int maxdac; @@ -532,11 +530,12 @@ static int parse_pins1(WPMINFO const struct matrox_bios* bd) { case 1: maxdac = 220000; break; default: maxdac = 240000; break; } - if (get_u16(bd->pins + 24)) { - maxdac = get_u16(bd->pins + 24) * 10; + if (get_unaligned_le16(bd->pins + 24)) { + maxdac = get_unaligned_le16(bd->pins + 24) * 10; } MINFO->limits.pixel.vcomax = maxdac; - MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000; + MINFO->values.pll.system = get_unaligned_le16(bd->pins + 28) ? + get_unaligned_le16(bd->pins + 28) * 10 : 50000; /* ignore 4MB, 8MB, module clocks */ MINFO->features.pll.ref_freq = 14318; MINFO->values.reg.mctlwtst = 0x00030101; @@ -575,7 +574,8 @@ static void default_pins2(WPMINFO2) { static int parse_pins3(WPMINFO const struct matrox_bios* bd) { MINFO->limits.pixel.vcomax = MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000); - MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ? + 0x01250A21 : get_unaligned_le32(bd->pins + 48); /* memory config */ MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) | ((bd->pins[57] << 22) & 0x00C00000) | @@ -601,7 +601,7 @@ static void default_pins3(WPMINFO2) { static int parse_pins4(WPMINFO const struct matrox_bios* bd) { MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000; MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000; - MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 71); MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) | ((bd->pins[87] << 22) & 0x00C00000) | ((bd->pins[86] << 1) & 0x000001E0) | @@ -609,7 +609,7 @@ static int parse_pins4(WPMINFO const struct matrox_bios* bd) { MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) | ((bd->pins[53] << 22) & 0x10000000) | ((bd->pins[53] << 7) & 0x00001C00); - MINFO->values.reg.opt3 = get_u32(bd->pins + 67); + MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 67); MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000; MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000; return 0; @@ -640,12 +640,12 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) { MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult; MINFO->values.pll.system = MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000; - MINFO->values.reg.opt = get_u32(bd->pins+ 48); - MINFO->values.reg.opt2 = get_u32(bd->pins+ 52); - MINFO->values.reg.opt3 = get_u32(bd->pins+ 94); - MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98); - MINFO->values.reg.memmisc = get_u32(bd->pins+102); - MINFO->values.reg.memrdbk = get_u32(bd->pins+106); + MINFO->values.reg.opt = get_unaligned_le32(bd->pins + 48); + MINFO->values.reg.opt2 = get_unaligned_le32(bd->pins + 52); + MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 94); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 98); + MINFO->values.reg.memmisc = get_unaligned_le32(bd->pins + 102); + MINFO->values.reg.memrdbk = get_unaligned_le32(bd->pins + 106); MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000; MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20; MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0; diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index e9a89fd82757..cc4c038a1b3f 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c @@ -13,12 +13,10 @@ * Corporation. http://support.eink.com/community * * This driver is written to be used with the Metronome display controller. - * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board - * using the Lyre interface board. + * It is intended to be architecture independent. A board specific driver + * must be used to perform all the physical IO interactions. An example + * is provided as am200epd.c * - * General notes: - * - User must set metronomefb_enable=1 to enable it. - * - See Documentation/fb/metronomefb.txt for how metronome works. */ #include <linux/module.h> #include <linux/kernel.h> @@ -38,9 +36,11 @@ #include <linux/uaccess.h> #include <linux/irq.h> -#include <asm/arch/pxa-regs.h> +#include <video/metronomefb.h> + #include <asm/unaligned.h> + #define DEBUG 1 #ifdef DEBUG #define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) @@ -53,35 +53,6 @@ #define DPY_W 832 #define DPY_H 622 -struct metromem_desc { - u32 mFDADR0; - u32 mFSADR0; - u32 mFIDR0; - u32 mLDCMD0; -}; - -struct metromem_cmd { - u16 opcode; - u16 args[((64-2)/2)]; - u16 csum; -}; - -struct metronomefb_par { - unsigned char *metromem; - struct metromem_desc *metromem_desc; - struct metromem_cmd *metromem_cmd; - unsigned char *metromem_wfm; - unsigned char *metromem_img; - u16 *metromem_img_csum; - u16 *csum_table; - int metromemsize; - dma_addr_t metromem_dma; - dma_addr_t metromem_desc_dma; - struct fb_info *info; - wait_queue_head_t waitq; - u8 frame_count; -}; - /* frame differs from image. frame includes non-visible pixels */ struct epd_frame { int fw; /* frame width */ @@ -120,8 +91,7 @@ static struct fb_var_screeninfo metronomefb_var __devinitdata = { .transp = { 0, 0, 0 }, }; -static unsigned int metronomefb_enable; - +/* the waveform structure that is coming from userspace firmware */ struct waveform_hdr { u8 stuff[32]; @@ -236,8 +206,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, } /* check waveform mode table address checksum */ - wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta)); - wmta &= 0x00FFFFFF; + wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF; cksum_idx = wmta + m*4 + 3; if (cksum_idx > size) return -EINVAL; @@ -249,8 +218,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, } /* check waveform temperature table address checksum */ - tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4))); - tta &= 0x00FFFFFF; + tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF; cksum_idx = tta + trn*4 + 3; if (cksum_idx > size) return -EINVAL; @@ -263,8 +231,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, /* here we do the real work of putting the waveform into the metromem buffer. this does runlength decoding of the waveform */ - wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4))); - wfm_idx &= 0x00FFFFFF; + wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF; owfm_idx = wfm_idx; if (wfm_idx > size) return -EINVAL; @@ -301,165 +268,6 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, return 0; } -/* register offsets for gpio control */ -#define LED_GPIO_PIN 51 -#define STDBY_GPIO_PIN 48 -#define RST_GPIO_PIN 49 -#define RDY_GPIO_PIN 32 -#define ERR_GPIO_PIN 17 -#define PCBPWR_GPIO_PIN 16 - -#define AF_SEL_GPIO_N 0x3 -#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) -#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) -#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) -#define GPDR1_OFFSET(pin) (pin - 32) -#define GPCR1_OFFSET(pin) (pin - 32) -#define GPSR1_OFFSET(pin) (pin - 32) -#define GPCR0_OFFSET(pin) (pin) -#define GPSR0_OFFSET(pin) (pin) - -static void metronome_set_gpio_output(int pin, int val) -{ - u8 index; - - index = pin >> 4; - - switch (index) { - case 1: - if (val) - GPSR0 |= (1 << GPSR0_OFFSET(pin)); - else - GPCR0 |= (1 << GPCR0_OFFSET(pin)); - break; - case 2: - break; - case 3: - if (val) - GPSR1 |= (1 << GPSR1_OFFSET(pin)); - else - GPCR1 |= (1 << GPCR1_OFFSET(pin)); - break; - default: - printk(KERN_ERR "unimplemented\n"); - } -} - -static void __devinit metronome_init_gpio_pin(int pin, int dir) -{ - u8 index; - /* dir 0 is output, 1 is input - - do 2 things here: - - set gpio alternate function to standard gpio - - set gpio direction to input or output */ - - index = pin >> 4; - switch (index) { - case 1: - GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); - - if (dir) - GPDR0 &= ~(1 << pin); - else - GPDR0 |= (1 << pin); - break; - case 2: - GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); - - if (dir) - GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); - else - GPDR1 |= (1 << GPDR1_OFFSET(pin)); - break; - case 3: - GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); - - if (dir) - GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); - else - GPDR1 |= (1 << GPDR1_OFFSET(pin)); - break; - default: - printk(KERN_ERR "unimplemented\n"); - } -} - -static void __devinit metronome_init_gpio_regs(void) -{ - metronome_init_gpio_pin(LED_GPIO_PIN, 0); - metronome_set_gpio_output(LED_GPIO_PIN, 0); - - metronome_init_gpio_pin(STDBY_GPIO_PIN, 0); - metronome_set_gpio_output(STDBY_GPIO_PIN, 0); - - metronome_init_gpio_pin(RST_GPIO_PIN, 0); - metronome_set_gpio_output(RST_GPIO_PIN, 0); - - metronome_init_gpio_pin(RDY_GPIO_PIN, 1); - - metronome_init_gpio_pin(ERR_GPIO_PIN, 1); - - metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0); - metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0); -} - -static void metronome_disable_lcd_controller(struct metronomefb_par *par) -{ - LCSR = 0xffffffff; /* Clear LCD Status Register */ - LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ - - /* we reset and just wait for things to settle */ - msleep(200); -} - -static void metronome_enable_lcd_controller(struct metronomefb_par *par) -{ - LCSR = 0xffffffff; - FDADR0 = par->metromem_desc_dma; - LCCR0 |= LCCR0_ENB; -} - -static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par) -{ - /* here we do: - - disable the lcd controller - - setup lcd control registers - - setup dma descriptor - - reenable lcd controller - */ - - /* disable the lcd controller */ - metronome_disable_lcd_controller(par); - - /* setup lcd control registers */ - LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS - | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; - - LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */ - | (27 << 10) /* hsync pulse width - 1 */ - | (33 << 16) /* eol pixel count */ - | (33 << 24); /* bol pixel count */ - - LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */ - | (24 << 10) /* vsync pulse width - 1 */ - | (2 << 16) /* eof pixel count */ - | (0 << 24); /* bof pixel count */ - - LCCR3 = 2 /* pixel clock divisor */ - | (24 << 8) /* AC Bias pin freq */ - | LCCR3_16BPP /* BPP */ - | LCCR3_PCP; /* PCP falling edge */ - - /* setup dma descriptor */ - par->metromem_desc->mFDADR0 = par->metromem_desc_dma; - par->metromem_desc->mFSADR0 = par->metromem_dma; - par->metromem_desc->mFIDR0 = 0; - par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw - * epd_frame_table[0].fh; - /* reenable lcd controller */ - metronome_enable_lcd_controller(par); -} - static int metronome_display_cmd(struct metronomefb_par *par) { int i; @@ -493,8 +301,7 @@ static int metronome_display_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = opcode; /* display cmd */ - i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event_intr(par); } static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) @@ -518,13 +325,12 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; msleep(1); - metronome_set_gpio_output(RST_GPIO_PIN, 1); + par->board->set_rst(par, 1); msleep(1); - metronome_set_gpio_output(STDBY_GPIO_PIN, 1); + par->board->set_stdby(par, 1); - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_config_cmd(struct metronomefb_par *par) @@ -569,8 +375,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = 0xCC10; /* config cmd */ - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_init_cmd(struct metronomefb_par *par) @@ -596,16 +401,19 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = 0xCC20; /* init cmd */ - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_init_regs(struct metronomefb_par *par) { int res; - metronome_init_gpio_regs(); - metronome_init_lcdc_regs(par); + par->board->init_gpio_regs(par); + + par->board->init_lcdc_regs(par); + + /* now that lcd is setup, setup dma descriptor */ + par->board->post_dma_setup(par); res = metronome_powerup_cmd(par); if (res) @@ -616,8 +424,6 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) return res; res = metronome_init_cmd(par); - if (res) - return res; return res; } @@ -632,7 +438,7 @@ static void metronomefb_dpy_update(struct metronomefb_par *par) cksum = calc_img_cksum((u16 *) par->metromem_img, (epd_frame_table[0].fw * DPY_H)/2); - *((u16 *) (par->metromem_img) + + *((u16 *)(par->metromem_img) + (epd_frame_table[0].fw * DPY_H)/2) = cksum; metronome_display_cmd(par); } @@ -641,8 +447,8 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index) { int i; u16 csum = 0; - u16 *buf = (u16 __force *) (par->info->screen_base + index); - u16 *img = (u16 *) (par->metromem_img + index); + u16 *buf = (u16 __force *)(par->info->screen_base + index); + u16 *img = (u16 *)(par->metromem_img + index); /* swizzle from vm to metromem and recalc cksum at the same time*/ for (i = 0; i < PAGE_SIZE/2; i++) { @@ -678,7 +484,7 @@ static void metronomefb_fillrect(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_fillrect(info, rect); + sys_fillrect(info, rect); metronomefb_dpy_update(par); } @@ -687,7 +493,7 @@ static void metronomefb_copyarea(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_copyarea(info, area); + sys_copyarea(info, area); metronomefb_dpy_update(par); } @@ -696,7 +502,7 @@ static void metronomefb_imageblit(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_imageblit(info, image); + sys_imageblit(info, image); metronomefb_dpy_update(par); } @@ -733,7 +539,7 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf, count = total_size - p; } - dst = (void __force *) (info->screen_base + p); + dst = (void __force *)(info->screen_base + p); if (copy_from_user(dst, buf, count)) err = -EFAULT; @@ -759,18 +565,10 @@ static struct fb_deferred_io metronomefb_defio = { .deferred_io = metronomefb_dpy_deferred_io, }; -static irqreturn_t metronome_handle_irq(int irq, void *dev_id) -{ - struct fb_info *info = dev_id; - struct metronomefb_par *par = info->par; - - wake_up_interruptible(&par->waitq); - return IRQ_HANDLED; -} - static int __devinit metronomefb_probe(struct platform_device *dev) { struct fb_info *info; + struct metronome_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; @@ -779,17 +577,26 @@ static int __devinit metronomefb_probe(struct platform_device *dev) int cmd_size, wfm_size, img_size, padding_size, totalsize; int i; + /* pick up board specific routines */ + board = dev->dev.platform_data; + if (!board) + return -EINVAL; + + /* try to count device specific driver, if can't, platform recalls */ + if (!try_module_get(board->owner)) + return -ENODEV; + /* we have two blocks of memory. info->screen_base which is vm, and is the fb used by apps. par->metromem which is physically contiguous memory and contains the display controller commands, waveform, processed image data and padding. this is the data pulled - by the pxa255's LCD controller and pushed to Metronome */ + by the device's LCD controller and pushed to Metronome */ videomemorysize = (DPY_W*DPY_H); videomemory = vmalloc(videomemorysize); if (!videomemory) - return retval; + return -ENOMEM; memset(videomemory, 0, videomemorysize); @@ -797,7 +604,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) if (!info) goto err_vfree; - info->screen_base = (char __iomem *) videomemory; + info->screen_base = (char __force __iomem *)videomemory; info->fbops = &metronomefb_ops; info->var = metronomefb_var; @@ -805,6 +612,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) info->fix.smem_len = videomemorysize; par = info->par; par->info = info; + par->board = board; init_waitqueue_head(&par->waitq); /* this table caches per page csum values. */ @@ -849,11 +657,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev) par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size + img_size + padding_size; - /* load the waveform in. assume mode 3, temp 31 for now */ - /* a) request the waveform file from userspace + /* load the waveform in. assume mode 3, temp 31 for now + a) request the waveform file from userspace b) process waveform and decode into metromem */ - - retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev); + retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); if (retval < 0) { printk(KERN_ERR "metronomefb: couldn't get waveform\n"); goto err_dma_free; @@ -861,19 +668,14 @@ static int __devinit metronomefb_probe(struct platform_device *dev) retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, par->metromem_wfm, 3, 31, &par->frame_count); + release_firmware(fw_entry); if (retval < 0) { printk(KERN_ERR "metronomefb: couldn't process waveform\n"); - goto err_ld_wfm; + goto err_dma_free; } - release_firmware(fw_entry); - retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq, - IRQF_DISABLED, "Metronome", info); - if (retval) { - dev_err(&dev->dev, "request_irq failed: %d\n", retval); - goto err_ld_wfm; - } - set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); + if (board->setup_irq(info)) + goto err_dma_free; retval = metronome_init_regs(par); if (retval < 0) @@ -913,9 +715,7 @@ err_cmap: err_fb_rel: framebuffer_release(info); err_free_irq: - free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); -err_ld_wfm: - release_firmware(fw_entry); + board->free_irq(info); err_dma_free: dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, par->metromem_dma); @@ -923,6 +723,7 @@ err_csum_table: vfree(par->csum_table); err_vfree: vfree(videomemory); + module_put(board->owner); return retval; } @@ -939,7 +740,8 @@ static int __devexit metronomefb_remove(struct platform_device *dev) vfree(par->csum_table); unregister_framebuffer(info); vfree((void __force *)info->screen_base); - free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); + par->board->free_irq(info); + module_put(par->board->owner); framebuffer_release(info); } return 0; @@ -949,48 +751,21 @@ static struct platform_driver metronomefb_driver = { .probe = metronomefb_probe, .remove = metronomefb_remove, .driver = { + .owner = THIS_MODULE, .name = "metronomefb", }, }; -static struct platform_device *metronomefb_device; - static int __init metronomefb_init(void) { - int ret; - - if (!metronomefb_enable) { - printk(KERN_ERR - "Use metronomefb_enable to enable the device\n"); - return -ENXIO; - } - - ret = platform_driver_register(&metronomefb_driver); - if (!ret) { - metronomefb_device = platform_device_alloc("metronomefb", 0); - if (metronomefb_device) - ret = platform_device_add(metronomefb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(metronomefb_device); - platform_driver_unregister(&metronomefb_driver); - } - } - return ret; - + return platform_driver_register(&metronomefb_driver); } static void __exit metronomefb_exit(void) { - platform_device_unregister(metronomefb_device); platform_driver_unregister(&metronomefb_driver); } -module_param(metronomefb_enable, uint, 0); -MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome"); - module_init(metronomefb_init); module_exit(metronomefb_exit); diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 08d072552233..473562191586 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -22,7 +22,7 @@ ((v).xres == (x) && (v).yres == (y)) #ifdef DEBUG -#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __func__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -522,7 +522,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; - u32 best, diff; + u32 best, diff, tdiff; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { @@ -651,19 +651,27 @@ done: return (refresh_specified) ? 2 : 1; } - diff = xres + yres; + diff = 2 * (xres + yres); best = -1; DPRINTK("Trying best-fit modes\n"); for (i = 0; i < dbsize; i++) { - if (xres <= db[i].xres && yres <= db[i].yres) { DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); if (!fb_try_mode(var, info, &db[i], bpp)) { - if (diff > (db[i].xres - xres) + (db[i].yres - yres)) { - diff = (db[i].xres - xres) + (db[i].yres - yres); - best = i; - } + tdiff = abs(db[i].xres - xres) + + abs(db[i].yres - yres); + + /* + * Penalize modes with resolutions smaller + * than requested. + */ + if (xres > db[i].xres || yres > db[i].yres) + tdiff += xres + yres; + + if (diff > tdiff) { + diff = tdiff; + best = i; + } } - } } if (best != -1) { fb_try_mode(var, info, &db[best], bpp); diff --git a/drivers/video/n411.c b/drivers/video/n411.c new file mode 100644 index 000000000000..935830fea7b6 --- /dev/null +++ b/drivers/video/n411.c @@ -0,0 +1,202 @@ +/* + * linux/drivers/video/n411.c -- Platform device for N411 EPD kit + * + * Copyright (C) 2008, Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This driver is written to be used with the Hecuba display controller + * board, and tested with the EInk 800x600 display in 1 bit mode. + * The interface between Hecuba and the host is TTL based GPIO. The + * GPIO requirements are 8 writable data lines and 6 lines for control. + * Only 4 of the controls are actually used here but 6 for future use. + * The driver requires the IO addresses for data and control GPIO at + * load time. It is also possible to use this display with a standard + * PC parallel port. + * + * General notes: + * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <video/hecubafb.h> + +static unsigned long dio_addr; +static unsigned long cio_addr; +static unsigned long c2io_addr; +static unsigned long splashval; +static unsigned int nosplash; +static unsigned char ctl; + +static void n411_set_ctl(struct hecubafb_par *par, unsigned char bit, unsigned + char state) +{ + switch (bit) { + case HCB_CD_BIT: + if (state) + ctl &= ~(HCB_CD_BIT); + else + ctl |= HCB_CD_BIT; + break; + case HCB_DS_BIT: + if (state) + ctl &= ~(HCB_DS_BIT); + else + ctl |= HCB_DS_BIT; + break; + } + outb(ctl, cio_addr); +} + +static unsigned char n411_get_ctl(struct hecubafb_par *par) +{ + return inb(c2io_addr); +} + +static void n411_set_data(struct hecubafb_par *par, unsigned char value) +{ + outb(value, dio_addr); +} + +static void n411_wait_for_ack(struct hecubafb_par *par, int clear) +{ + int timeout; + unsigned char tmp; + + timeout = 500; + do { + tmp = n411_get_ctl(par); + if ((tmp & HCB_ACK_BIT) && (!clear)) + return; + else if (!(tmp & HCB_ACK_BIT) && (clear)) + return; + udelay(1); + } while (timeout--); + printk(KERN_ERR "timed out waiting for ack\n"); +} + +static int n411_init_control(struct hecubafb_par *par) +{ + unsigned char tmp; + /* for init, we want the following setup to be set: + WUP = lo + ACK = hi + DS = hi + RW = hi + CD = lo + */ + + /* write WUP to lo, DS to hi, RW to hi, CD to lo */ + ctl = HCB_WUP_BIT | HCB_RW_BIT | HCB_CD_BIT ; + n411_set_ctl(par, HCB_DS_BIT, 1); + + /* check ACK is not lo */ + tmp = n411_get_ctl(par); + if (tmp & HCB_ACK_BIT) { + printk(KERN_ERR "Fail because ACK is already low\n"); + return -ENXIO; + } + + return 0; +} + + +static int n411_init_board(struct hecubafb_par *par) +{ + int retval; + + retval = n411_init_control(par); + if (retval) + return retval; + + par->send_command(par, APOLLO_INIT_DISPLAY); + par->send_data(par, 0x81); + + /* have to wait while display resets */ + udelay(1000); + + /* if we were told to splash the screen, we just clear it */ + if (!nosplash) { + par->send_command(par, APOLLO_ERASE_DISPLAY); + par->send_data(par, splashval); + } + + return 0; +} + +static struct hecuba_board n411_board = { + .owner = THIS_MODULE, + .init = n411_init_board, + .set_ctl = n411_set_ctl, + .set_data = n411_set_data, + .wait_for_ack = n411_wait_for_ack, +}; + +static struct platform_device *n411_device; +static int __init n411_init(void) +{ + int ret; + if (!dio_addr || !cio_addr || !c2io_addr) { + printk(KERN_WARNING "no IO addresses supplied\n"); + return -EINVAL; + } + + /* request our platform independent driver */ + request_module("hecubafb"); + + n411_device = platform_device_alloc("hecubafb", -1); + if (!n411_device) + return -ENOMEM; + + platform_device_add_data(n411_device, &n411_board, sizeof(n411_board)); + + /* this _add binds hecubafb to n411. hecubafb refcounts n411 */ + ret = platform_device_add(n411_device); + + if (ret) + platform_device_put(n411_device); + + return ret; + +} + +static void __exit n411_exit(void) +{ + platform_device_unregister(n411_device); +} + +module_init(n411_init); +module_exit(n411_exit); + +module_param(nosplash, uint, 0); +MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); +module_param(dio_addr, ulong, 0); +MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); +module_param(cio_addr, ulong, 0); +MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); +module_param(c2io_addr, ulong, 0); +MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); +module_param(splashval, ulong, 0); +MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); + +MODULE_DESCRIPTION("board driver for n411 hecuba/apollo epd kit"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index d1a10549f543..ed20a9871b33 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c @@ -129,7 +129,7 @@ typedef struct { int nvclk_khz; char mem_page_miss; char mem_latency; - int memory_type; + u32 memory_type; int memory_width; char enable_video; char gr_during_vid; @@ -719,7 +719,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, memctrl >>= 16; if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { - int dimm[3]; + u32 dimm[3]; dev = pci_get_bus_and_slot(0, 2); pci_read_config_dword(dev, 0x40, &dimm[0]); diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 82579d3a9970..d9627b57eb4d 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -265,12 +265,12 @@ static void nv10GetConfig(struct nvidia_par *par) dev = pci_get_bus_and_slot(0, 1); if ((par->Chipset & 0xffff) == 0x01a0) { - int amt = 0; + u32 amt; pci_read_config_dword(dev, 0x7c, &amt); par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; } else if ((par->Chipset & 0xffff) == 0x01f0) { - int amt = 0; + u32 amt; pci_read_config_dword(dev, 0x84, &amt); par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 596652d2831f..9dbb5a5a267b 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -43,14 +43,14 @@ #define NVTRACE if (0) printk #endif -#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) -#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__) #ifdef CONFIG_FB_NVIDIA_DEBUG #define assert(expr) \ if (!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ BUG(); \ } #else @@ -1559,7 +1559,6 @@ static int __devinit nvidiafb_init(void) module_init(nvidiafb_init); -#ifdef MODULE static void __exit nvidiafb_exit(void) { pci_unregister_driver(&nvidiafb_driver); @@ -1615,5 +1614,3 @@ MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " MODULE_AUTHOR("Antonino Daplas"); MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset"); MODULE_LICENSE("GPL"); -#endif /* MODULE */ - diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 452433d46973..d7b3dcc0dc43 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -248,7 +248,7 @@ static void __iomem *offb_map_reg(struct device_node *np, int index, static void __init offb_init_fb(const char *name, const char *full_name, int width, int height, int depth, int pitch, unsigned long address, - struct device_node *dp) + int foreign_endian, struct device_node *dp) { unsigned long res_size = pitch * height * (depth + 7) / 8; struct offb_par *par = &default_par; @@ -397,7 +397,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, info->screen_base = ioremap(address, fix->smem_len); info->par = par; info->pseudo_palette = (void *) (info + 1); - info->flags = FBINFO_DEFAULT; + info->flags = FBINFO_DEFAULT | foreign_endian; fb_alloc_cmap(&info->cmap, 256, 0); @@ -424,6 +424,15 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) u64 rstart, address = OF_BAD_ADDR; const u32 *pp, *addrp, *up; u64 asize; + int foreign_endian = 0; + +#ifdef __BIG_ENDIAN + if (of_get_property(dp, "little-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#else + if (of_get_property(dp, "big-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#endif pp = of_get_property(dp, "linux,bootx-depth", &len); if (pp == NULL) @@ -509,7 +518,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) offb_init_fb(no_real_node ? "bootx" : dp->name, no_real_node ? "display" : dp->full_name, width, height, depth, pitch, address, - no_real_node ? NULL : dp); + foreign_endian, no_real_node ? NULL : dp); } } diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 58496061142d..c95874fe9076 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -310,7 +310,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: p9100 at %lx:%lx\n", + printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 30181b593829..3f1ca2adda3d 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -56,7 +56,7 @@ #undef PM2FB_MASTER_DEBUG #ifdef PM2FB_MASTER_DEBUG #define DPRINTK(a, b...) \ - printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) + printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b) #else #define DPRINTK(a, b...) #endif @@ -67,7 +67,7 @@ * Driver data */ static int hwcursor = 1; -static char *mode __devinitdata; +static char *mode_option __devinitdata; /* * The XFree GLINT driver will (I think to implement hardware cursor @@ -1680,17 +1680,19 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, info->pixmap.scan_align = 1; } - if (!mode) - mode = "640x480@60"; + if (!mode_option) + mode_option = "640x480@60"; - err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); + err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err || err == 4) info->var = pm2fb_var; - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) goto err_exit_both; - if (register_framebuffer(info) < 0) + retval = register_framebuffer(info); + if (retval < 0) goto err_exit_all; printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", @@ -1797,7 +1799,7 @@ static int __init pm2fb_setup(char *options) else if (!strncmp(this_opt, "noaccel", 7)) noaccel = 1; else - mode = this_opt; + mode_option = this_opt; } return 0; } @@ -1833,8 +1835,10 @@ static void __exit pm2fb_exit(void) #ifdef MODULE module_exit(pm2fb_exit); -module_param(mode, charp, 0); -MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); module_param(lowhsync, bool, 0); MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); module_param(lowvsync, bool, 0); diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 5dba8cdd0517..68089d1456c2 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -45,7 +45,7 @@ #undef PM3FB_MASTER_DEBUG #ifdef PM3FB_MASTER_DEBUG #define DPRINTK(a, b...) \ - printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) + printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b) #else #define DPRINTK(a, b...) #endif @@ -1571,6 +1571,8 @@ module_exit(pm3fb_exit); #endif module_init(pm3fb_init); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "Disable acceleration"); module_param(hwcursor, int, 0644); diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 757651954e6c..3ab6e3d973a1 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 d920b8a14c35..8238dc826429 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/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 5c47968e7f21..d94c57ffbdb1 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -56,10 +56,6 @@ #include "rivafb.h" #include "nvreg.h" -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - /* version number of this driver */ #define RIVAFB_VERSION "0.9.5b" @@ -74,14 +70,14 @@ #define NVTRACE if(0) printk #endif -#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) -#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__) #ifdef CONFIG_FB_RIVA_DEBUG #define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ BUG(); \ } #else @@ -2213,14 +2209,12 @@ static int __devinit rivafb_init(void) module_init(rivafb_init); -#ifdef MODULE static void __exit rivafb_exit(void) { pci_unregister_driver(&rivafb_driver); } module_exit(rivafb_exit); -#endif /* MODULE */ module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "bool: disable acceleration"); diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c index a11026812d1b..f3694cf17e58 100644 --- a/drivers/video/riva/nv_driver.c +++ b/drivers/video/riva/nv_driver.c @@ -41,11 +41,6 @@ #include "rivafb.h" #include "nvreg.h" - -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - #define PFX "rivafb: " static inline unsigned char MISCin(struct riva_par *par) @@ -163,7 +158,7 @@ unsigned long riva_get_memlen(struct riva_par *par) unsigned long memlen = 0; unsigned int chipset = par->Chipset; struct pci_dev* dev; - int amt; + u32 amt; switch (chip->Architecture) { case NV_ARCH_03: diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index 13307703a9f0..78fdbf5178d7 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c @@ -231,7 +231,7 @@ typedef struct { int nvclk_khz; char mem_page_miss; char mem_latency; - int memory_type; + u32 memory_type; int memory_width; char enable_video; char gr_during_vid; @@ -2107,7 +2107,7 @@ static void nv10GetConfig ) { struct pci_dev* dev; - int amt; + u32 amt; #ifdef __BIG_ENDIAN /* turn on big endian register access */ diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 71fa6edb5c47..13b38cbbe4cf 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -430,9 +430,9 @@ static void s3c2410fb_activate_var(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2; - dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); - dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); - dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); + dprintk("%s: var->xres = %d\n", __func__, var->xres); + dprintk("%s: var->yres = %d\n", __func__, var->yres); + dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel); if (type == S3C2410_LCDCON1_TFT) { s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 7d53bc23b9c7..2972f112dbed 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -132,10 +132,10 @@ static const struct svga_timing_regs s3_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option __devinitdata = "640x480-8@60"; #ifdef CONFIG_MTRR -static int mtrr = 1; +static int mtrr __devinitdata = 1; #endif static int fasttext = 1; @@ -145,8 +145,10 @@ MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge"); -module_param(mode, charp, 0444); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0444); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0444); +MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -886,7 +888,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct s3fb_info), NULL); + info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev)); if (!info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -901,13 +903,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "s3fb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -919,7 +921,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -960,22 +962,22 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebuffer\n"); + dev_err(info->dev, "cannot register framebuffer\n"); goto err_reg_fb; } @@ -1051,7 +1053,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct s3fb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1083,7 +1085,7 @@ static int s3_pci_resume(struct pci_dev* dev) struct s3fb_info *par = info->par; int err; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1100,7 +1102,7 @@ static int s3_pci_resume(struct pci_dev* dev) if (err) { mutex_unlock(&(par->open_lock)); release_console_sem(); - dev_err(&(dev->dev), "error %d enabling device for resume\n", err); + dev_err(info->dev, "error %d enabling device for resume\n", err); return err; } pci_set_master(dev); @@ -1168,7 +1170,7 @@ static int __init s3fb_setup(char *options) else if (!strncmp(opt, "fasttext:", 9)) fasttext = simple_strtoul(opt + 9, NULL, 0); else - mode = opt; + mode_option = opt; } return 0; diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h index 48066ef3af05..f465b27ed860 100644 --- a/drivers/video/sa1100fb.h +++ b/drivers/video/sa1100fb.h @@ -132,7 +132,7 @@ struct sa1100fb_info { * Debug macros */ #if DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 35c1ce62b216..783d4adffb93 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -140,7 +140,7 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, chan->adapter.id = I2C_HW_B_SAVAGE; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->pcidev->dev; - chan->algo.udelay = 40; + chan->algo.udelay = 10; chan->algo.timeout = 20; chan->algo.data = chan; diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index 9b05da6268f7..a14e82211037 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -55,7 +55,7 @@ #undef SISFBDEBUG #ifdef SISFBDEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #define TWDEBUG(x) printk(KERN_INFO x "\n"); #else #define DPRINTK(fmt, args...) diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 97784f9c184d..5b11a00f49bc 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -1006,7 +1006,7 @@ static int sst_set_pll_att_ti(struct fb_info *info, break; default: dprintk("%s: wrong clock code '%d'\n", - __FUNCTION__, clock); + __func__, clock); return 0; } udelay(300); @@ -1048,7 +1048,7 @@ static int sst_set_pll_ics(struct fb_info *info, break; default: dprintk("%s: wrong clock code '%d'\n", - __FUNCTION__, clock); + __func__, clock); return 0; } udelay(300); @@ -1079,7 +1079,7 @@ static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp) sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP); break; default: - dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + dprintk("%s: bad depth '%u'\n", __func__, bpp); break; } } @@ -1093,7 +1093,7 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp) sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP); break; default: - dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + dprintk("%s: bad depth '%u'\n", __func__, bpp); break; } } @@ -1133,7 +1133,7 @@ static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par * } if (!ret) return 0; - f_dprintk("%s found %s\n", __FUNCTION__, dacs[i].name); + f_dprintk("%s found %s\n", __func__, dacs[i].name); par->dac_sw = dacs[i]; return 1; } diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index f98be301140c..598d35eff935 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -164,11 +164,11 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; # define DEBUG_ON() debug_on=1 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \ printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \ - __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \ + __func__, reg, value, READ_BYTE(fb,reg)); \ gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0) # define WRITE_WORD(value,fb,reg) do { if (debug_on) \ printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \ - __FUNCTION__, reg, value, READ_WORD(fb,reg)); \ + __func__, reg, value, READ_WORD(fb,reg)); \ gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0) #endif /* DEBUG_STIFB_REGS */ diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c index 37af10ab8f52..a352d5f46bbf 100644 --- a/drivers/video/syscopyarea.c +++ b/drivers/video/syscopyarea.c @@ -26,15 +26,15 @@ */ static void -bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (!shift) { /* Same alignment for source and dest */ @@ -167,8 +167,8 @@ bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, */ static void -bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int shift; @@ -186,8 +186,8 @@ bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, shift = dst_idx-src_idx; - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); + first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); + last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); if (!shift) { /* Same alignment for source and dest */ @@ -353,7 +353,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); } } else { @@ -362,7 +362,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c index a261e9e6a675..f94d6b6e29ee 100644 --- a/drivers/video/sysfillrect.c +++ b/drivers/video/sysfillrect.c @@ -22,16 +22,16 @@ */ static void -bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -78,16 +78,16 @@ bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -132,8 +132,8 @@ bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long val = pat; unsigned long first, last; @@ -141,8 +141,8 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -188,16 +188,17 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, + int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -267,9 +268,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (!left) { - void (*fill_op32)(unsigned long *dst, int dst_idx, - unsigned long pat, unsigned n, int bits) = - NULL; + void (*fill_op32)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, unsigned n, + int bits) = NULL; switch (rect->rop) { case ROP_XOR: @@ -287,16 +288,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -318,7 +319,7 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c index bd7e7e9d155f..186c6f607be2 100644 --- a/drivers/video/sysimgblt.c +++ b/drivers/video/sysimgblt.c @@ -18,35 +18,31 @@ #define DEBUG #ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) #else #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -72,7 +68,7 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, val = 0; if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, start_index)); val = *dst & start_mask; shift = start_index; @@ -83,20 +79,20 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift); if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -125,8 +121,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, u32 i, j, l; dst2 = dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -137,7 +133,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write leading bits */ if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, + start_index)); val = *dst & start_mask; shift = start_index; } @@ -145,13 +142,13 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift); + val |= FB_SHIFT_HIGH(p, color, shift); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -160,7 +157,7 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write trailing bits */ if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -199,10 +196,10 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p, switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index e5a9ddb3c8be..a71774305772 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -419,7 +419,7 @@ static int __devinit tcx_init_one(struct of_device *op) par->mmap_map[6].size = SBUS_MMAP_EMPTY; } - par->physbase = 0; + par->physbase = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { @@ -470,10 +470,10 @@ static int __devinit tcx_init_one(struct of_device *op) dev_set_drvdata(&op->dev, info); - printk("%s: TCX at %lx:%lx, %s\n", + printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, - op->resource[0].start, + par->physbase, par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; @@ -527,7 +527,7 @@ static struct of_platform_driver tcx_driver = { .remove = __devexit_p(tcx_remove), }; -int __init tcx_init(void) +static int __init tcx_init(void) { if (fb_get_options("tcxfb", NULL)) return -ENODEV; @@ -535,7 +535,7 @@ int __init tcx_init(void) return of_register_driver(&tcx_driver, &of_bus_type); } -void __exit tcx_exit(void) +static void __exit tcx_exit(void) { of_unregister_driver(&tcx_driver); } diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 71e179ea5f95..ea9f19d25597 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -70,7 +70,7 @@ #include <video/tdfx.h> -#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b) +#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b) #ifdef CONFIG_MTRR #include <asm/mtrr.h> diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 0a4e07d43d2d..bd54cd0de39a 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -58,7 +58,7 @@ static int displaytype; /* defaults which are normally overriden by user values */ /* video mode */ -static char *mode = "640x480"; +static char *mode_option __devinitdata = "640x480"; static int bpp = 8; static int noaccel; @@ -73,7 +73,10 @@ static int memsize; static int memdiff; static int nativex; -module_param(mode, charp, 0); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); module_param(bpp, int, 0); module_param(center, int, 0); module_param(stretch, int, 0); @@ -1297,7 +1300,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, #endif fb_info.pseudo_palette = pseudo_pal; - if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) { + if (!fb_find_mode(&default_var, &fb_info, + mode_option, NULL, 0, NULL, bpp)) { err = -EINVAL; goto out_unmap2; } @@ -1385,7 +1389,7 @@ static struct pci_driver tridentfb_pci_driver = { * video=trident:800x600,bpp=16,noaccel */ #ifndef MODULE -static int tridentfb_setup(char *options) +static int __init tridentfb_setup(char *options) { char *opt; if (!options || !*options) @@ -1412,7 +1416,7 @@ static int tridentfb_setup(char *options) else if (!strncmp(opt, "nativex=", 8)) nativex = simple_strtoul(opt + 8, NULL, 0); else - mode = opt; + mode_option = opt; } return 0; } diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 93361656316c..cdbb56edb6cb 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -181,7 +181,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task) /* If all slots are taken -- bail out. */ if (uvfb_tasks[seq]) { mutex_unlock(&uvfb_lock); - return -EBUSY; + err = -EBUSY; + goto out; } /* Save a pointer to the kernel part of the task struct. */ @@ -205,7 +206,6 @@ static int uvesafb_exec(struct uvesafb_ktask *task) err = cn_netlink_send(m, 0, gfp_any()); } } - kfree(m); if (!err && !(task->t.flags & TF_EXIT)) err = !wait_for_completion_timeout(task->done, @@ -218,7 +218,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task) seq++; if (seq >= UVESAFB_TASKS_MAX) seq = 0; - +out: + kfree(m); return err; } @@ -885,7 +886,7 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) } /* fb_find_mode() failed */ - if (i == 0 || i >= 3) { + if (i == 0) { info->var.xres = 640; info->var.yres = 480; mode = (struct fb_videomode *) diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 2aa71eb67c2b..c18f1884b550 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -112,8 +112,9 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order, /* * It seems like __get_free_pages only ups the usage count - * of the first page. This doesn't work with nopage mapping, so - * up the usage count once more. + * of the first page. This doesn't work with fault mapping, so + * up the usage count once more (XXX: should use split_page or + * compound page). */ memset((void *)va->logical, 0x00, va->size); diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 4c3a63308df1..536ab11623f0 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -100,7 +100,7 @@ static struct svga_timing_regs vt8623_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option = "640x480-8@60"; #ifdef CONFIG_MTRR static int mtrr = 1; @@ -110,8 +110,10 @@ MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]"); -module_param(mode, charp, 0644); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0644); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -434,6 +436,10 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wcrt_multi(vt8623_offset_regs, offset_value); svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); + /* Clear H/V Skew */ + svga_wcrt_mask(0x03, 0x00, 0x60); + svga_wcrt_mask(0x05, 0x00, 0x60); + if (info->var.vmode & FB_VMODE_DOUBLE) svga_wcrt_mask(0x09, 0x80, 0x80); else @@ -655,7 +661,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL); + info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev)); if (! info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -671,13 +677,13 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "vt8623fb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -690,14 +696,14 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap_1; } par->mmio_base = pci_iomap(dev, 1, 0); if (! par->mmio_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for MMIO failed\n"); + dev_err(info->dev, "iomap for MMIO failed\n"); goto err_iomap_2; } @@ -708,7 +714,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) info->screen_size = memsize1 << 20; else { - dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); + dev_err(info->dev, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); info->screen_size = 16 << 20; } @@ -722,22 +728,22 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebugger\n"); + dev_err(info->dev, "cannot register framebugger\n"); goto err_reg_fb; } @@ -811,7 +817,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -842,7 +848,7 @@ static int vt8623_pci_resume(struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -913,7 +919,7 @@ static int __init vt8623fb_init(void) return -ENODEV; if (option && *option) - mode = option; + mode_option = option; #endif pr_debug("vt8623fb: initializing\n"); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 003c49a490eb..30469bf906e5 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -765,8 +765,10 @@ int __init w100fb_probe(struct platform_device *pdev) printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; out: - fb_dealloc_cmap(&info->cmap); - kfree(info->pseudo_palette); + if (info) { + fb_dealloc_cmap(&info->cmap); + kfree(info->pseudo_palette); + } if (remapped_fbuf != NULL) iounmap(remapped_fbuf); if (remapped_regs != NULL) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index b535483bc556..13866789b356 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -80,19 +80,51 @@ static void add_status(struct virtio_device *dev, unsigned status) dev->config->set_status(dev, dev->config->get_status(dev) | status); } +void virtio_check_driver_offered_feature(const struct virtio_device *vdev, + unsigned int fbit) +{ + unsigned int i; + struct virtio_driver *drv = container_of(vdev->dev.driver, + struct virtio_driver, driver); + + for (i = 0; i < drv->feature_table_size; i++) + if (drv->feature_table[i] == fbit) + return; + BUG(); +} +EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); + static int virtio_dev_probe(struct device *_d) { - int err; + int err, i; struct virtio_device *dev = container_of(_d,struct virtio_device,dev); struct virtio_driver *drv = container_of(dev->dev.driver, struct virtio_driver, driver); + u32 device_features; + /* We have a driver! */ add_status(dev, VIRTIO_CONFIG_S_DRIVER); + + /* Figure out what features the device supports. */ + device_features = dev->config->get_features(dev); + + /* Features supported by both device and driver into dev->features. */ + memset(dev->features, 0, sizeof(dev->features)); + for (i = 0; i < drv->feature_table_size; i++) { + unsigned int f = drv->feature_table[i]; + BUG_ON(f >= 32); + if (device_features & (1 << f)) + set_bit(f, dev->features); + } + err = drv->probe(dev); if (err) add_status(dev, VIRTIO_CONFIG_S_FAILED); - else + else { add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); + /* They should never have set feature bits beyond 32 */ + dev->config->set_features(dev, dev->features[0]); + } return err; } @@ -114,6 +146,8 @@ static int virtio_dev_remove(struct device *_d) int register_virtio_driver(struct virtio_driver *driver) { + /* Catch this early. */ + BUG_ON(driver->feature_table_size && !driver->feature_table); driver->driver.bus = &virtio_bus; driver->driver.probe = virtio_dev_probe; driver->driver.remove = virtio_dev_remove; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 0b3efc31ee6d..bfef604160d1 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -155,9 +155,9 @@ static void virtballoon_changed(struct virtio_device *vdev) static inline s64 towards_target(struct virtio_balloon *vb) { u32 v; - __virtio_config_val(vb->vdev, - offsetof(struct virtio_balloon_config, num_pages), - &v); + vb->vdev->config->get(vb->vdev, + offsetof(struct virtio_balloon_config, num_pages), + &v, sizeof(v)); return v - vb->num_pages; } @@ -227,7 +227,7 @@ static int virtballoon_probe(struct virtio_device *vdev) } vb->tell_host_first - = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST); + = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST); return 0; @@ -259,7 +259,11 @@ static void virtballoon_remove(struct virtio_device *vdev) kfree(vb); } +static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST }; + static struct virtio_driver virtio_balloon = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index c0df924766a7..27e9fc9117cd 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -87,23 +87,22 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) return container_of(vdev, struct virtio_pci_device, vdev); } -/* virtio config->feature() implementation */ -static bool vp_feature(struct virtio_device *vdev, unsigned bit) +/* virtio config->get_features() implementation */ +static u32 vp_get_features(struct virtio_device *vdev) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + + /* When someone needs more than 32 feature bits, we'll need to + * steal a bit to indicate that the rest are somewhere else. */ + return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); +} + +/* virtio config->set_features() implementation */ +static void vp_set_features(struct virtio_device *vdev, u32 features) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); - u32 mask; - - /* Since this function is supposed to have the side effect of - * enabling a queried feature, we simulate that by doing a read - * from the host feature bitmask and then writing to the guest - * feature bitmask */ - mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); - if (mask & (1 << bit)) { - mask |= (1 << bit); - iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); - } - return !!(mask & (1 << bit)); + iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); } /* virtio config->get() implementation */ @@ -145,14 +144,14 @@ static void vp_set_status(struct virtio_device *vdev, u8 status) struct virtio_pci_device *vp_dev = to_vp_device(vdev); /* We should never be setting status to 0. */ BUG_ON(status == 0); - return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); + iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); } static void vp_reset(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); /* 0 status means a reset. */ - return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); + iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); } /* the notify function used when creating a virt queue */ @@ -293,7 +292,6 @@ static void vp_del_vq(struct virtqueue *vq) } static struct virtio_config_ops virtio_pci_config_ops = { - .feature = vp_feature, .get = vp_get, .set = vp_set, .get_status = vp_get_status, @@ -301,6 +299,8 @@ static struct virtio_config_ops virtio_pci_config_ops = { .reset = vp_reset, .find_vq = vp_find_vq, .del_vq = vp_del_vq, + .get_features = vp_get_features, + .set_features = vp_set_features, }; /* the PCI probing function */ diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index c2fa5c630813..937a49d6772c 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -184,6 +184,11 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) START_USE(vq); + if (unlikely(vq->broken)) { + END_USE(vq); + return NULL; + } + if (!more_used(vq)) { pr_debug("No more buffers in queue\n"); END_USE(vq); diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h index fe6bdf43380f..e6ab7cf08f88 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 diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index 2ce4cebc31d9..099b6fb5b5cb 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -13,6 +13,7 @@ #include <linux/types.h> #include <linux/zorro.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -76,36 +77,58 @@ proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t * } static const struct file_operations proc_bus_zorro_operations = { + .owner = THIS_MODULE, .llseek = proc_bus_zorro_lseek, .read = proc_bus_zorro_read, }; -static int -get_zorro_dev_info(char *buf, char **start, off_t pos, int count) +static void * zorro_seq_start(struct seq_file *m, loff_t *pos) { - u_int slot; - off_t at = 0; - int len, cnt; - - for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) { - struct zorro_dev *z = &zorro_autocon[slot]; - len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, - z->id, (unsigned long)zorro_resource_start(z), - (unsigned long)zorro_resource_len(z), - z->rom.er_Type); - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - } - } - return (count > cnt) ? cnt : count; + return (*pos < zorro_num_autocon) ? pos : NULL; +} + +static void * zorro_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < zorro_num_autocon) ? pos : NULL; +} + +static void zorro_seq_stop(struct seq_file *m, void *v) +{ +} + +static int zorro_seq_show(struct seq_file *m, void *v) +{ + u_int slot = *(loff_t *)v; + struct zorro_dev *z = &zorro_autocon[slot]; + + seq_printf(m, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, z->id, + (unsigned long)zorro_resource_start(z), + (unsigned long)zorro_resource_len(z), + z->rom.er_Type); + return 0; +} + +static const struct seq_operations zorro_devices_seq_ops = { + .start = zorro_seq_start, + .next = zorro_seq_next, + .stop = zorro_seq_stop, + .show = zorro_seq_show, +}; + +static int zorro_devices_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &zorro_devices_seq_ops); } +static const struct file_operations zorro_devices_proc_fops = { + .owner = THIS_MODULE, + .open = zorro_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static struct proc_dir_entry *proc_bus_zorro_dir; static int __init zorro_proc_attach_device(u_int slot) @@ -114,11 +137,11 @@ static int __init zorro_proc_attach_device(u_int slot) char name[4]; sprintf(name, "%02x", slot); - entry = create_proc_entry(name, 0, proc_bus_zorro_dir); + entry = proc_create_data(name, 0, proc_bus_zorro_dir, + &proc_bus_zorro_operations, + &zorro_autocon[slot]); if (!entry) return -ENOMEM; - entry->proc_fops = &proc_bus_zorro_operations; - entry->data = &zorro_autocon[slot]; entry->size = sizeof(struct zorro_dev); return 0; } @@ -128,9 +151,9 @@ static int __init zorro_proc_init(void) u_int slot; if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { - proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_zorro_dir, - get_zorro_dev_info); + proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL); + proc_create("devices", 0, proc_bus_zorro_dir, + &zorro_devices_proc_fops); for (slot = 0; slot < zorro_num_autocon; slot++) zorro_proc_attach_device(slot); } |