diff options
Diffstat (limited to 'drivers')
565 files changed, 15185 insertions, 8044 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 0f9d4be7ed7..f4f000abc4e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -11,7 +11,7 @@ config ACPI bool "ACPI Support" depends on IA64 || X86 depends on PCI - select PM + depends on PM default y ---help--- Advanced Configuration and Power Interface (ACPI) support for @@ -97,6 +97,7 @@ config ACPI_BATTERY config ACPI_BUTTON tristate "Button" + depends on INPUT default y help This driver handles events on the power, sleep and lid buttons. @@ -172,6 +173,7 @@ config ACPI_NUMA config ACPI_ASUS tristate "ASUS/Medion Laptop Extras" depends on X86 + select BACKLIGHT_CLASS_DEVICE ---help--- This driver provides support for extra features of ACPI-compatible ASUS laptops. As some of Medion laptops are made by ASUS, it may also @@ -200,6 +202,7 @@ config ACPI_ASUS config ACPI_IBM tristate "IBM ThinkPad Laptop Extras" depends on X86 + select BACKLIGHT_CLASS_DEVICE ---help--- This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video @@ -225,6 +228,7 @@ config ACPI_IBM_DOCK config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on X86 + select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings on "legacy free" Toshiba laptops. These laptops can be recognized by diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 11abc7bf777..6daeace796a 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -109,7 +109,7 @@ static struct proc_dir_entry *acpi_ac_dir; static int acpi_ac_seq_show(struct seq_file *seq, void *offset) { - struct acpi_ac *ac = (struct acpi_ac *)seq->private; + struct acpi_ac *ac = seq->private; if (!ac) @@ -187,7 +187,7 @@ static int acpi_ac_remove_fs(struct acpi_device *device) static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_ac *ac = (struct acpi_ac *)data; + struct acpi_ac *ac = data; struct acpi_device *device = NULL; @@ -221,10 +221,9 @@ static int acpi_ac_add(struct acpi_device *device) if (!device) return -EINVAL; - ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL); + ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL); if (!ac) return -ENOMEM; - memset(ac, 0, sizeof(struct acpi_ac)); ac->device = device; strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME); @@ -269,7 +268,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - ac = (struct acpi_ac *)acpi_driver_data(device); + ac = acpi_driver_data(device); status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_ac_notify); diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 6bcd9e8e7bc..cd946ed192d 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -395,10 +395,9 @@ static int acpi_memory_device_add(struct acpi_device *device) if (!device) return -EINVAL; - mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL); + mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL); if (!mem_device) return -ENOMEM; - memset(mem_device, 0, sizeof(struct acpi_memory_device)); INIT_LIST_HEAD(&mem_device->res_list); mem_device->device = device; @@ -429,7 +428,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - mem_device = (struct acpi_memory_device *)acpi_driver_data(device); + mem_device = acpi_driver_data(device); kfree(mem_device); return 0; diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index c7ac9297a20..396140bbbe5 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -35,6 +35,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/proc_fs.h> +#include <linux/backlight.h> #include <acpi/acpi_drivers.h> #include <acpi/acpi_bus.h> #include <asm/uaccess.h> @@ -402,6 +403,8 @@ static struct model_data model_conf[END_MODEL] = { /* procdir we use */ static struct proc_dir_entry *asus_proc_dir; +static struct backlight_device *asus_backlight_device; + /* * This header is made available to allow proper configuration given model, * revision number , ... this info cannot go in struct asus_hotk because it is @@ -779,7 +782,7 @@ proc_write_lcd(struct file *file, const char __user * buffer, return rv; } -static int read_brightness(void) +static int read_brightness(struct backlight_device *bd) { int value; @@ -801,9 +804,10 @@ static int read_brightness(void) /* * Change the brightness level */ -static void set_brightness(int value) +static int set_brightness(int value) { acpi_status status = 0; + int ret = 0; /* SPLV laptop */ if (hotk->methods->brightness_set) { @@ -811,11 +815,12 @@ static void set_brightness(int value) value, NULL)) printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); - return; + ret = -EIO; + goto out; } /* No SPLV method if we are here, act as appropriate */ - value -= read_brightness(); + value -= read_brightness(NULL); while (value != 0) { status = acpi_evaluate_object(NULL, (value > 0) ? hotk->methods->brightness_up : @@ -825,15 +830,22 @@ static void set_brightness(int value) if (ACPI_FAILURE(status)) printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); + ret = -EIO; } - return; +out: + return ret; +} + +static int set_brightness_status(struct backlight_device *bd) +{ + return set_brightness(bd->props->brightness); } static int proc_read_brn(char *page, char **start, off_t off, int count, int *eof, void *data) { - return sprintf(page, "%d\n", read_brightness()); + return sprintf(page, "%d\n", read_brightness(NULL)); } static int @@ -1134,7 +1146,7 @@ static int asus_hotk_get_info(void) if (ACPI_FAILURE(status)) printk(KERN_WARNING " Couldn't get the DSDT table header\n"); else - asus_info = (struct acpi_table_header *)dsdt.pointer; + asus_info = dsdt.pointer; /* We have to write 0 on init this far for all ASUS models */ if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { @@ -1156,7 +1168,7 @@ static int asus_hotk_get_info(void) * asus_model_match() and try something completely different. */ if (buffer.pointer) { - model = (union acpi_object *)buffer.pointer; + model = buffer.pointer; switch (model->type) { case ACPI_TYPE_STRING: string = model->string.pointer; @@ -1252,11 +1264,9 @@ static int asus_hotk_add(struct acpi_device *device) printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", ASUS_ACPI_VERSION); - hotk = - (struct asus_hotk *)kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); + hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); if (!hotk) return -ENOMEM; - memset(hotk, 0, sizeof(struct asus_hotk)); hotk->handle = device->handle; strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME); @@ -1333,6 +1343,26 @@ static int asus_hotk_remove(struct acpi_device *device, int type) return 0; } +static struct backlight_properties asus_backlight_data = { + .owner = THIS_MODULE, + .get_brightness = read_brightness, + .update_status = set_brightness_status, + .max_brightness = 15, +}; + +static void __exit asus_acpi_exit(void) +{ + if (asus_backlight_device) + backlight_device_unregister(asus_backlight_device); + + acpi_bus_unregister_driver(&asus_hotk_driver); + remove_proc_entry(PROC_ASUS, acpi_root_dir); + + kfree(asus_info); + + return; +} + static int __init asus_acpi_init(void) { int result; @@ -1370,17 +1400,15 @@ static int __init asus_acpi_init(void) return result; } - return 0; -} - -static void __exit asus_acpi_exit(void) -{ - acpi_bus_unregister_driver(&asus_hotk_driver); - remove_proc_entry(PROC_ASUS, acpi_root_dir); - - kfree(asus_info); + asus_backlight_device = backlight_device_register("asus",NULL,NULL, + &asus_backlight_data); + if (IS_ERR(asus_backlight_device)) { + printk(KERN_ERR "Could not register asus backlight device\n"); + asus_backlight_device = NULL; + asus_acpi_exit(); + } - return; + return 0; } module_init(asus_acpi_init); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 026e40755cd..5f43e0d1489 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -149,7 +149,7 @@ acpi_battery_get_info(struct acpi_battery *battery, return -ENODEV; } - package = (union acpi_object *)buffer.pointer; + package = buffer.pointer; /* Extract Package Data */ @@ -160,12 +160,11 @@ acpi_battery_get_info(struct acpi_battery *battery, goto end; } - data.pointer = kmalloc(data.length, GFP_KERNEL); + data.pointer = kzalloc(data.length, GFP_KERNEL); if (!data.pointer) { result = -ENOMEM; goto end; } - memset(data.pointer, 0, data.length); status = acpi_extract_package(package, &format, &data); if (ACPI_FAILURE(status)) { @@ -179,7 +178,7 @@ acpi_battery_get_info(struct acpi_battery *battery, kfree(buffer.pointer); if (!result) - (*bif) = (struct acpi_battery_info *)data.pointer; + (*bif) = data.pointer; return result; } @@ -209,7 +208,7 @@ acpi_battery_get_status(struct acpi_battery *battery, return -ENODEV; } - package = (union acpi_object *)buffer.pointer; + package = buffer.pointer; /* Extract Package Data */ @@ -220,12 +219,11 @@ acpi_battery_get_status(struct acpi_battery *battery, goto end; } - data.pointer = kmalloc(data.length, GFP_KERNEL); + data.pointer = kzalloc(data.length, GFP_KERNEL); if (!data.pointer) { result = -ENOMEM; goto end; } - memset(data.pointer, 0, data.length); status = acpi_extract_package(package, &format, &data); if (ACPI_FAILURE(status)) { @@ -239,7 +237,7 @@ acpi_battery_get_status(struct acpi_battery *battery, kfree(buffer.pointer); if (!result) - (*bst) = (struct acpi_battery_status *)data.pointer; + (*bst) = data.pointer; return result; } @@ -334,7 +332,7 @@ static struct proc_dir_entry *acpi_battery_dir; static int acpi_battery_read_info(struct seq_file *seq, void *offset) { int result = 0; - struct acpi_battery *battery = (struct acpi_battery *)seq->private; + struct acpi_battery *battery = seq->private; struct acpi_battery_info *bif = NULL; char *units = "?"; @@ -418,7 +416,7 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) static int acpi_battery_read_state(struct seq_file *seq, void *offset) { int result = 0; - struct acpi_battery *battery = (struct acpi_battery *)seq->private; + struct acpi_battery *battery = seq->private; struct acpi_battery_status *bst = NULL; char *units = "?"; @@ -494,7 +492,7 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) { - struct acpi_battery *battery = (struct acpi_battery *)seq->private; + struct acpi_battery *battery = seq->private; char *units = "?"; @@ -531,8 +529,8 @@ acpi_battery_write_alarm(struct file *file, { int result = 0; char alarm_string[12] = { '\0' }; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_battery *battery = (struct acpi_battery *)m->private; + struct seq_file *m = file->private_data; + struct acpi_battery *battery = m->private; if (!battery || (count > sizeof(alarm_string) - 1)) @@ -658,7 +656,7 @@ static int acpi_battery_remove_fs(struct acpi_device *device) static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_battery *battery = (struct acpi_battery *)data; + struct acpi_battery *battery = data; struct acpi_device *device = NULL; @@ -694,10 +692,9 @@ static int acpi_battery_add(struct acpi_device *device) if (!device) return -EINVAL; - battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL); + battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); if (!battery) return -ENOMEM; - memset(battery, 0, sizeof(struct acpi_battery)); battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); @@ -742,7 +739,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - battery = (struct acpi_battery *)acpi_driver_data(device); + battery = acpi_driver_data(device); status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 279c4bac92e..766332e4559 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -561,6 +561,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_IOSAPIC: message = "IOSAPIC"; break; + case ACPI_IRQ_MODEL_PLATFORM: + message = "platform specific model"; + break; default: printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); return -ENODEV; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 5ef885e82c7..ac860583c20 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -29,6 +29,7 @@ #include <linux/types.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/input.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -62,7 +63,7 @@ #define _COMPONENT ACPI_BUTTON_COMPONENT ACPI_MODULE_NAME("acpi_button") - MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); MODULE_LICENSE("GPL"); @@ -78,12 +79,14 @@ static struct acpi_driver acpi_button_driver = { .ops = { .add = acpi_button_add, .remove = acpi_button_remove, - }, + }, }; struct acpi_button { struct acpi_device *device; /* Fixed button kludge */ - u8 type; + unsigned int type; + struct input_dev *input; + char phys[32]; /* for input device */ unsigned long pushed; }; @@ -109,8 +112,7 @@ static struct proc_dir_entry *acpi_button_dir; static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) { - struct acpi_button *button = (struct acpi_button *)seq->private; - + struct acpi_button *button = seq->private; if (!button || !button->device) return 0; @@ -128,22 +130,17 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file) static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) { - struct acpi_button *button = (struct acpi_button *)seq->private; + struct acpi_button *button = seq->private; acpi_status status; unsigned long state; - if (!button || !button->device) return 0; status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state); - if (ACPI_FAILURE(status)) { - seq_printf(seq, "state: unsupported\n"); - } else { - seq_printf(seq, "state: %s\n", - (state ? "open" : "closed")); - } - + seq_printf(seq, "state: %s\n", + ACPI_FAILURE(status) ? "unsupported" : + (state ? "open" : "closed")); return 0; } @@ -159,8 +156,7 @@ static struct proc_dir_entry *acpi_lid_dir; static int acpi_button_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; - struct acpi_button *button = NULL; - + struct acpi_button *button; if (!device || !acpi_driver_data(device)) return -EINVAL; @@ -228,10 +224,8 @@ static int acpi_button_add_fs(struct acpi_device *device) static int acpi_button_remove_fs(struct acpi_device *device) { - struct acpi_button *button = NULL; - + struct acpi_button *button = acpi_driver_data(device); - button = acpi_driver_data(device); if (acpi_device_dir(device)) { if (button->type == ACPI_BUTTON_TYPE_LID) remove_proc_entry(ACPI_BUTTON_FILE_STATE, @@ -253,14 +247,34 @@ static int acpi_button_remove_fs(struct acpi_device *device) static void acpi_button_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_button *button = (struct acpi_button *)data; - + struct acpi_button *button = data; + struct input_dev *input; if (!button || !button->device) return; switch (event) { case ACPI_BUTTON_NOTIFY_STATUS: + input = button->input; + + if (button->type == ACPI_BUTTON_TYPE_LID) { + struct acpi_handle *handle = button->device->handle; + unsigned long state; + + if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID", + NULL, &state))) + input_report_switch(input, SW_LID, !state); + + } else { + int keycode = test_bit(KEY_SLEEP, input->keybit) ? + KEY_SLEEP : KEY_POWER; + + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + } + input_sync(input); + acpi_bus_generate_event(button->device, event, ++button->pushed); break; @@ -275,8 +289,7 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) static acpi_status acpi_button_notify_fixed(void *data) { - struct acpi_button *button = (struct acpi_button *)data; - + struct acpi_button *button = data; if (!button) return AE_BAD_PARAMETER; @@ -286,24 +299,75 @@ static acpi_status acpi_button_notify_fixed(void *data) return AE_OK; } -static int acpi_button_add(struct acpi_device *device) +static int acpi_button_install_notify_handlers(struct acpi_button *button) { - int result = 0; - acpi_status status = AE_OK; - struct acpi_button *button = NULL; + acpi_status status; + switch (button->type) { + case ACPI_BUTTON_TYPE_POWERF: + status = + acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_button_notify_fixed, + button); + break; + case ACPI_BUTTON_TYPE_SLEEPF: + status = + acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_button_notify_fixed, + button); + break; + default: + status = acpi_install_notify_handler(button->device->handle, + ACPI_DEVICE_NOTIFY, + acpi_button_notify, + button); + break; + } + + return ACPI_FAILURE(status) ? -ENODEV : 0; +} + +static void acpi_button_remove_notify_handlers(struct acpi_button *button) +{ + switch (button->type) { + case ACPI_BUTTON_TYPE_POWERF: + acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_button_notify_fixed); + break; + case ACPI_BUTTON_TYPE_SLEEPF: + acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_button_notify_fixed); + break; + default: + acpi_remove_notify_handler(button->device->handle, + ACPI_DEVICE_NOTIFY, + acpi_button_notify); + break; + } +} + +static int acpi_button_add(struct acpi_device *device) +{ + int error; + struct acpi_button *button; + struct input_dev *input; if (!device) return -EINVAL; - button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL); + button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); if (!button) return -ENOMEM; - memset(button, 0, sizeof(struct acpi_button)); button->device = device; acpi_driver_data(device) = button; + button->input = input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto err_free_button; + } + /* * Determine the button type (via hid), as fixed-feature buttons * need to be handled a bit differently than generic-space. @@ -338,39 +402,48 @@ static int acpi_button_add(struct acpi_device *device) } else { printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", acpi_device_hid(device)); - result = -ENODEV; - goto end; + error = -ENODEV; + goto err_free_input; } - result = acpi_button_add_fs(device); - if (result) - goto end; + error = acpi_button_add_fs(device); + if (error) + goto err_free_input; + + error = acpi_button_install_notify_handlers(button); + if (error) + goto err_remove_fs; + + snprintf(button->phys, sizeof(button->phys), + "%s/button/input0", acpi_device_hid(device)); + + input->name = acpi_device_name(device); + input->phys = button->phys; + input->id.bustype = BUS_HOST; + input->id.product = button->type; switch (button->type) { + case ACPI_BUTTON_TYPE_POWER: case ACPI_BUTTON_TYPE_POWERF: - status = - acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_button_notify_fixed, - button); + input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_POWER, input->keybit); break; + + case ACPI_BUTTON_TYPE_SLEEP: case ACPI_BUTTON_TYPE_SLEEPF: - status = - acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_button_notify_fixed, - button); + input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_SLEEP, input->keybit); break; - default: - status = acpi_install_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, - acpi_button_notify, - button); + + case ACPI_BUTTON_TYPE_LID: + input->evbit[0] = BIT(EV_SW); + set_bit(SW_LID, input->swbit); break; } - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } + error = input_register_device(input); + if (error) + goto err_remove_handlers; if (device->wakeup.flags.valid) { /* Button's GPE is run-wake GPE */ @@ -385,47 +458,31 @@ static int acpi_button_add(struct acpi_device *device) printk(KERN_INFO PREFIX "%s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); - end: - if (result) { - acpi_button_remove_fs(device); - kfree(button); - } + return 0; - return result; + err_remove_handlers: + acpi_button_remove_notify_handlers(button); + err_remove_fs: + acpi_button_remove_fs(device); + err_free_input: + input_free_device(input); + err_free_button: + kfree(button); + return error; } static int acpi_button_remove(struct acpi_device *device, int type) { - acpi_status status = 0; - struct acpi_button *button = NULL; - + struct acpi_button *button; if (!device || !acpi_driver_data(device)) return -EINVAL; button = acpi_driver_data(device); - /* Unregister for device notifications. */ - switch (button->type) { - case ACPI_BUTTON_TYPE_POWERF: - status = - acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_button_notify_fixed); - break; - case ACPI_BUTTON_TYPE_SLEEPF: - status = - acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_button_notify_fixed); - break; - default: - status = acpi_remove_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, - acpi_button_notify); - break; - } - + acpi_button_remove_notify_handlers(button); acpi_button_remove_fs(device); - + input_unregister_device(button->input); kfree(button); return 0; @@ -433,8 +490,7 @@ static int acpi_button_remove(struct acpi_device *device, int type) static int __init acpi_button_init(void) { - int result = 0; - + int result; acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); if (!acpi_button_dir) @@ -451,7 +507,6 @@ static int __init acpi_button_init(void) static void __exit acpi_button_exit(void) { - acpi_bus_unregister_driver(&acpi_button_driver); if (acpi_power_dir) @@ -461,8 +516,6 @@ static void __exit acpi_button_exit(void) if (acpi_lid_dir) remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); - - return; } module_init(acpi_button_init); diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 871aa520ece..0a1863ec91f 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -96,11 +96,10 @@ static int acpi_container_add(struct acpi_device *device) return -EINVAL; } - container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL); + container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL); if (!container) return -ENOMEM; - memset(container, 0, sizeof(struct acpi_container)); container->handle = device->handle; strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS); @@ -117,7 +116,7 @@ static int acpi_container_remove(struct acpi_device *device, int type) acpi_status status = AE_OK; struct acpi_container *pc = NULL; - pc = (struct acpi_container *)acpi_driver_data(device); + pc = acpi_driver_data(device); kfree(pc); return status; } diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index bf5b79ed361..90990a4b652 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -27,6 +27,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/notifier.h> +#include <linux/platform_device.h> #include <linux/jiffies.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -39,13 +40,15 @@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); MODULE_LICENSE("GPL"); static struct atomic_notifier_head dock_notifier_list; +static struct platform_device dock_device; +static char dock_device_name[] = "dock"; struct dock_station { acpi_handle handle; unsigned long last_dock_time; u32 flags; spinlock_t dd_lock; - spinlock_t hp_lock; + struct mutex hp_lock; struct list_head dependent_devices; struct list_head hotplug_devices; }; @@ -115,9 +118,9 @@ static void dock_add_hotplug_device(struct dock_station *ds, struct dock_dependent_device *dd) { - spin_lock(&ds->hp_lock); + mutex_lock(&ds->hp_lock); list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); - spin_unlock(&ds->hp_lock); + mutex_unlock(&ds->hp_lock); } /** @@ -131,9 +134,9 @@ static void dock_del_hotplug_device(struct dock_station *ds, struct dock_dependent_device *dd) { - spin_lock(&ds->hp_lock); + mutex_lock(&ds->hp_lock); list_del(&dd->hotplug_list); - spin_unlock(&ds->hp_lock); + mutex_unlock(&ds->hp_lock); } /** @@ -296,7 +299,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; - spin_lock(&ds->hp_lock); + mutex_lock(&ds->hp_lock); /* * First call driver specific hotplug functions @@ -318,15 +321,17 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) else dock_create_acpi_device(dd->handle); } - spin_unlock(&ds->hp_lock); + mutex_unlock(&ds->hp_lock); } static void dock_event(struct dock_station *ds, u32 event, int num) { + struct device *dev = &dock_device.dev; /* - * we don't do events until someone tells me that - * they would like to have them. + * Indicate that the status of the dock station has + * changed. */ + kobject_uevent(&dev->kobj, KOBJ_CHANGE); } /** @@ -441,6 +446,9 @@ static int dock_in_progress(struct dock_station *ds) */ int register_dock_notifier(struct notifier_block *nb) { + if (!dock_station) + return -ENODEV; + return atomic_notifier_chain_register(&dock_notifier_list, nb); } @@ -452,6 +460,9 @@ EXPORT_SYMBOL_GPL(register_dock_notifier); */ void unregister_dock_notifier(struct notifier_block *nb) { + if (!dock_station) + return; + atomic_notifier_chain_unregister(&dock_notifier_list, nb); } @@ -512,6 +523,37 @@ void unregister_hotplug_dock_device(acpi_handle handle) EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); /** + * handle_eject_request - handle an undock request checking for error conditions + * + * Check to make sure the dock device is still present, then undock and + * hotremove all the devices that may need removing. + */ +static int handle_eject_request(struct dock_station *ds, u32 event) +{ + if (!dock_present(ds)) + return -ENODEV; + + if (dock_in_progress(ds)) + return -EBUSY; + + /* + * here we need to generate the undock + * event prior to actually doing the undock + * so that the device struct still exists. + */ + dock_event(ds, event, UNDOCK_EVENT); + hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + undock(ds); + eject_dock(ds); + if (dock_present(ds)) { + printk(KERN_ERR PREFIX "Unable to undock!\n"); + return -EBUSY; + } + + return 0; +} + +/** * dock_notify - act upon an acpi dock notification * @handle: the dock station handle * @event: the acpi event @@ -519,13 +561,11 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); * * If we are notified to dock, then check to see if the dock is * present and then dock. Notify all drivers of the dock event, - * and then hotplug and devices that may need hotplugging. For undock - * check to make sure the dock device is still present, then undock - * and hotremove all the devices that may need removing. + * and then hotplug and devices that may need hotplugging. */ static void dock_notify(acpi_handle handle, u32 event, void *data) { - struct dock_station *ds = (struct dock_station *)data; + struct dock_station *ds = data; switch (event) { case ACPI_NOTIFY_BUS_CHECK: @@ -553,19 +593,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) * to the driver who wish to hotplug. */ case ACPI_NOTIFY_EJECT_REQUEST: - if (!dock_in_progress(ds) && dock_present(ds)) { - /* - * here we need to generate the undock - * event prior to actually doing the undock - * so that the device struct still exists. - */ - dock_event(ds, event, UNDOCK_EVENT); - hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); - undock(ds); - eject_dock(ds); - if (dock_present(ds)) - printk(KERN_ERR PREFIX "Unable to undock!\n"); - } + handle_eject_request(ds, event); break; default: printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); @@ -588,7 +616,7 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; acpi_handle tmp; - struct dock_station *ds = (struct dock_station *)context; + struct dock_station *ds = context; struct dock_dependent_device *dd; status = acpi_bus_get_ejd(handle, &tmp); @@ -604,6 +632,33 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } +/* + * show_docked - read method for "docked" file in sysfs + */ +static ssize_t show_docked(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); + +} +DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); + +/* + * write_undock - write method for "undock" file in sysfs + */ +static ssize_t write_undock(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + + if (!count) + return -EINVAL; + + ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); + return ret ? ret: count; +} +DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); + /** * dock_add - add a new dock station * @handle: the dock station handle @@ -626,9 +681,33 @@ static int dock_add(acpi_handle handle) INIT_LIST_HEAD(&dock_station->dependent_devices); INIT_LIST_HEAD(&dock_station->hotplug_devices); spin_lock_init(&dock_station->dd_lock); - spin_lock_init(&dock_station->hp_lock); + mutex_init(&dock_station->hp_lock); ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); + /* initialize platform device stuff */ + dock_device.name = dock_device_name; + ret = platform_device_register(&dock_device); + if (ret) { + printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret); + kfree(dock_station); + return ret; + } + ret = device_create_file(&dock_device.dev, &dev_attr_docked); + if (ret) { + printk("Error %d adding sysfs file\n", ret); + platform_device_unregister(&dock_device); + kfree(dock_station); + return ret; + } + ret = device_create_file(&dock_device.dev, &dev_attr_undock); + if (ret) { + printk("Error %d adding sysfs file\n", ret); + device_remove_file(&dock_device.dev, &dev_attr_docked); + platform_device_unregister(&dock_device); + kfree(dock_station); + return ret; + } + /* Find dependent devices */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_dock_devices, dock_station, @@ -638,7 +717,8 @@ static int dock_add(acpi_handle handle) dd = alloc_dock_dependent_device(handle); if (!dd) { kfree(dock_station); - return -ENOMEM; + ret = -ENOMEM; + goto dock_add_err_unregister; } add_dock_dependent_device(dock_station, dd); @@ -658,8 +738,12 @@ static int dock_add(acpi_handle handle) return 0; dock_add_err: - kfree(dock_station); kfree(dd); +dock_add_err_unregister: + device_remove_file(&dock_device.dev, &dev_attr_docked); + device_remove_file(&dock_device.dev, &dev_attr_undock); + platform_device_unregister(&dock_device); + kfree(dock_station); return ret; } @@ -686,6 +770,11 @@ static int dock_remove(void) if (ACPI_FAILURE(status)) printk(KERN_ERR "Error removing notify handler\n"); + /* cleanup sysfs */ + device_remove_file(&dock_device.dev, &dev_attr_docked); + device_remove_file(&dock_device.dev, &dev_attr_undock); + platform_device_unregister(&dock_device); + /* free dock station memory */ kfree(dock_station); return 0; @@ -703,7 +792,7 @@ static int dock_remove(void) static acpi_status find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) { - int *count = (int *)context; + int *count = context; acpi_status status = AE_OK; if (is_dock(handle)) { @@ -726,7 +815,7 @@ static int __init dock_init(void) ACPI_UINT32_MAX, find_dock, &num, NULL); if (!num) - return -ENODEV; + printk(KERN_INFO "No dock devices found.\n"); return 0; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e6d4b084dca..cbdf031f3c0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -45,35 +45,34 @@ ACPI_MODULE_NAME("acpi_ec") #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" - +#undef PREFIX +#define PREFIX "ACPI: EC: " /* EC status register */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ - /* EC commands */ -#define ACPI_EC_COMMAND_READ 0x80 -#define ACPI_EC_COMMAND_WRITE 0x81 -#define ACPI_EC_BURST_ENABLE 0x82 -#define ACPI_EC_BURST_DISABLE 0x83 -#define ACPI_EC_COMMAND_QUERY 0x84 - +enum ec_command { + ACPI_EC_COMMAND_READ = 0x80, + ACPI_EC_COMMAND_WRITE = 0x81, + ACPI_EC_BURST_ENABLE = 0x82, + ACPI_EC_BURST_DISABLE = 0x83, + ACPI_EC_COMMAND_QUERY = 0x84, +}; /* EC events */ -enum { +enum ec_event { ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ - ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ + ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ }; -#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ +#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 /* Poll @ 100us increments */ -#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ -enum { - EC_INTR = 1, /* Output buffer full */ - EC_POLL, /* Input buffer empty */ -}; +static enum ec_mode { + EC_INTR = 1, /* Output buffer full */ + EC_POLL, /* Input buffer empty */ +} acpi_ec_mode = EC_INTR; static int acpi_ec_remove(struct acpi_device *device, int type); static int acpi_ec_start(struct acpi_device *device); @@ -93,22 +92,21 @@ static struct acpi_driver acpi_ec_driver = { }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ -struct acpi_ec { +static struct acpi_ec { acpi_handle handle; unsigned long uid; - unsigned long gpe_bit; + unsigned long gpe; unsigned long command_addr; unsigned long data_addr; unsigned long global_lock; - struct semaphore sem; - unsigned int expect_event; + struct mutex lock; + atomic_t query_pending; atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ wait_queue_head_t wait; } *ec_ecdt; /* External interfaces use first EC only, so remember */ static struct acpi_device *first_ec; -static int acpi_ec_mode = EC_INTR; /* -------------------------------------------------------------------------- Transaction Management @@ -134,54 +132,41 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) outb(data, ec->data_addr); } -static int acpi_ec_check_status(u8 status, u8 event) +static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) { - switch (event) { - case ACPI_EC_EVENT_OBF_1: + u8 status = acpi_ec_read_status(ec); + + if (event == ACPI_EC_EVENT_OBF_1) { if (status & ACPI_EC_FLAG_OBF) return 1; - break; - case ACPI_EC_EVENT_IBF_0: + } else if (event == ACPI_EC_EVENT_IBF_0) { if (!(status & ACPI_EC_FLAG_IBF)) return 1; - break; - default: - break; } return 0; } -static int acpi_ec_wait(struct acpi_ec *ec, u8 event) +static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event) { - int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0; - long time_left; - - ec->expect_event = event; - if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { - ec->expect_event = 0; - return 0; - } - - do { - if (acpi_ec_mode == EC_POLL) { - udelay(ACPI_EC_UDELAY); - } else { - time_left = wait_event_timeout(ec->wait, - !ec->expect_event, - msecs_to_jiffies(ACPI_EC_DELAY)); - if (time_left > 0) { - ec->expect_event = 0; + if (acpi_ec_mode == EC_POLL) { + unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); + while (time_before(jiffies, delay)) { + if (acpi_ec_check_status(ec, event)) return 0; - } } - if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { - ec->expect_event = 0; + } else { + if (wait_event_timeout(ec->wait, + acpi_ec_check_status(ec, event), + msecs_to_jiffies(ACPI_EC_DELAY)) || + acpi_ec_check_status(ec, event)) { return 0; + } else { + printk(KERN_ERR PREFIX "acpi_ec_wait timeout," + " status = %d, expect_event = %d\n", + acpi_ec_read_status(ec), event); } - } while (--i > 0); - - ec->expect_event = 0; + } return -ETIME; } @@ -196,7 +181,6 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) u8 tmp = 0; u8 status = 0; - status = acpi_ec_read_status(ec); if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); @@ -212,7 +196,7 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) atomic_set(&ec->leaving_burst, 0); return 0; - end: + end: ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); return -1; } @@ -221,58 +205,68 @@ int acpi_ec_leave_burst_mode(struct acpi_ec *ec) { u8 status = 0; - status = acpi_ec_read_status(ec); - if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){ + if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) { status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); - if(status) + if (status) goto end; acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE); acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); } atomic_set(&ec->leaving_burst, 1); return 0; - end: + end: ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode")); return -1; } -#endif /* ACPI_FUTURE_USAGE */ +#endif /* ACPI_FUTURE_USAGE */ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) + const u8 * wdata, unsigned wdata_len, + u8 * rdata, unsigned rdata_len) { - int result; + int result = 0; acpi_ec_write_cmd(ec, command); - for (; wdata_len > 0; wdata_len --) { + for (; wdata_len > 0; --wdata_len) { result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); - if (result) - return result; + if (result) { + printk(KERN_ERR PREFIX + "write_cmd timeout, command = %d\n", command); + goto end; + } acpi_ec_write_data(ec, *(wdata++)); } - if (command == ACPI_EC_COMMAND_WRITE) { + if (!rdata_len) { result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); - if (result) - return result; + if (result) { + printk(KERN_ERR PREFIX + "finish-write timeout, command = %d\n", command); + goto end; + } + } else if (command == ACPI_EC_COMMAND_QUERY) { + atomic_set(&ec->query_pending, 0); } - for (; rdata_len > 0; rdata_len --) { + for (; rdata_len > 0; --rdata_len) { result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); - if (result) - return result; + if (result) { + printk(KERN_ERR PREFIX "read timeout, command = %d\n", + command); + goto end; + } *(rdata++) = acpi_ec_read_data(ec); } - - return 0; + end: + return result; } static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) + const u8 * wdata, unsigned wdata_len, + u8 * rdata, unsigned rdata_len) { int status; u32 glk; @@ -280,36 +274,40 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) return -EINVAL; - if (rdata) - memset(rdata, 0, rdata_len); + if (rdata) + memset(rdata, 0, rdata_len); + mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) return -ENODEV; } - down(&ec->sem); + + /* Make sure GPE is enabled before doing transaction */ + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); if (status) { - printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX + "input buffer is not empty, aborting transaction\n"); goto end; } - status = acpi_ec_transaction_unlocked(ec, command, - wdata, wdata_len, - rdata, rdata_len); + status = acpi_ec_transaction_unlocked(ec, command, + wdata, wdata_len, + rdata, rdata_len); -end: - up(&ec->sem); + end: if (ec->global_lock) acpi_release_global_lock(glk); + mutex_unlock(&ec->lock); return status; } -static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) +static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) { int result; u8 d; @@ -322,15 +320,15 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { - u8 wdata[2] = { address, data }; - return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, + u8 wdata[2] = { address, data }; + return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, wdata, 2, NULL, 0); } /* * Externally callable EC access functions. For now, assume 1 EC only */ -int ec_read(u8 addr, u8 *val) +int ec_read(u8 addr, u8 * val) { struct acpi_ec *ec; int err; @@ -369,9 +367,9 @@ int ec_write(u8 addr, u8 val) EXPORT_SYMBOL(ec_write); -extern int ec_transaction(u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len) +int ec_transaction(u8 command, + const u8 * wdata, unsigned wdata_len, + u8 * rdata, unsigned rdata_len) { struct acpi_ec *ec; @@ -386,65 +384,49 @@ extern int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); -static int acpi_ec_query(struct acpi_ec *ec, u8 *data) +static int acpi_ec_query(struct acpi_ec *ec, u8 * data) { int result; - u8 d; + u8 d; - if (!ec || !data) - return -EINVAL; + if (!ec || !data) + return -EINVAL; - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ - result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); - if (result) - return result; + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); + if (result) + return result; - if (!d) - return -ENODATA; + if (!d) + return -ENODATA; - *data = d; - return 0; + *data = d; + return 0; } /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ -struct acpi_ec_query_data { - acpi_handle handle; - u8 data; -}; - static void acpi_ec_gpe_query(void *ec_cxt) { struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; u8 value = 0; - static char object_name[8]; + char object_name[8]; - if (!ec) - goto end; - - value = acpi_ec_read_status(ec); - - if (!(value & ACPI_EC_FLAG_SCI)) - goto end; - - if (acpi_ec_query(ec, &value)) - goto end; + if (!ec || acpi_ec_query(ec, &value)) + return; snprintf(object_name, 8, "_Q%2.2X", value); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - - end: - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } static u32 acpi_ec_gpe_handler(void *data) @@ -453,22 +435,18 @@ static u32 acpi_ec_gpe_handler(void *data) u8 value; struct acpi_ec *ec = (struct acpi_ec *)data; - acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR); - value = acpi_ec_read_status(ec); - if (acpi_ec_mode == EC_INTR) { - if (acpi_ec_check_status(value, ec->expect_event)) { - ec->expect_event = 0; - wake_up(&ec->wait); - } + wake_up(&ec->wait); } - if (value & ACPI_EC_FLAG_SCI) { - status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); - return status == AE_OK ? - ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; + value = acpi_ec_read_status(ec); + if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { + atomic_set(&ec->query_pending, 1); + status = + acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, + ec); } - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); + return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } @@ -504,7 +482,6 @@ acpi_ec_space_handler(u32 function, acpi_integer f_v = 0; int i = 0; - if ((address > 0xFF) || !value || !handler_context) return AE_BAD_PARAMETER; @@ -518,7 +495,7 @@ acpi_ec_space_handler(u32 function, switch (function) { case ACPI_READ: temp = 0; - result = acpi_ec_read(ec, (u8) address, (u8 *) &temp); + result = acpi_ec_read(ec, (u8) address, (u8 *) & temp); break; case ACPI_WRITE: result = acpi_ec_write(ec, (u8) address, (u8) temp); @@ -571,18 +548,15 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset) { struct acpi_ec *ec = (struct acpi_ec *)seq->private; - if (!ec) goto end; - seq_printf(seq, "gpe bit: 0x%02x\n", - (u32) ec->gpe_bit); + seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe); seq_printf(seq, "ports: 0x%02x, 0x%02x\n", - (u32) ec->command_addr, - (u32) ec->data_addr); + (u32) ec->command_addr, (u32) ec->data_addr); seq_printf(seq, "use global lock: %s\n", ec->global_lock ? "yes" : "no"); - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); end: return 0; @@ -605,7 +579,6 @@ static int acpi_ec_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_ec_dir); @@ -648,18 +621,17 @@ static int acpi_ec_add(struct acpi_device *device) acpi_status status = AE_OK; struct acpi_ec *ec = NULL; - if (!device) return -EINVAL; - ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); + ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec) return -ENOMEM; - memset(ec, 0, sizeof(struct acpi_ec)); ec->handle = device->handle; ec->uid = -1; - init_MUTEX(&ec->sem); + mutex_init(&ec->lock); + atomic_set(&ec->query_pending, 0); if (acpi_ec_mode == EC_INTR) { atomic_set(&ec->leaving_burst, 1); init_waitqueue_head(&ec->wait); @@ -669,8 +641,7 @@ static int acpi_ec_add(struct acpi_device *device) acpi_driver_data(device) = ec; /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(ec->handle, "_GLK", NULL, - &ec->global_lock); + acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock); /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ @@ -679,7 +650,7 @@ static int acpi_ec_add(struct acpi_device *device) ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); - acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, &acpi_ec_gpe_handler); kfree(ec_ecdt); @@ -687,11 +658,10 @@ static int acpi_ec_add(struct acpi_device *device) /* Get GPE bit assignment (EC events). */ /* TODO: Add support for _GPE returning a package */ - status = - acpi_evaluate_integer(ec->handle, "_GPE", NULL, - &ec->gpe_bit); + status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment")); + ACPI_EXCEPTION((AE_INFO, status, + "Obtaining GPE bit assignment")); result = -ENODEV; goto end; } @@ -701,13 +671,13 @@ static int acpi_ec_add(struct acpi_device *device) goto end; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", - acpi_device_name(device), acpi_device_bid(device), - (u32) ec->gpe_bit)); + acpi_device_name(device), acpi_device_bid(device), + (u32) ec->gpe)); if (!first_ec) first_ec = device; - end: + end: if (result) kfree(ec); @@ -718,7 +688,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type) { struct acpi_ec *ec = NULL; - if (!device) return -EINVAL; @@ -761,7 +730,6 @@ static int acpi_ec_start(struct acpi_device *device) acpi_status status = AE_OK; struct acpi_ec *ec = NULL; - if (!device) return -EINVAL; @@ -782,27 +750,26 @@ static int acpi_ec_start(struct acpi_device *device) } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", - ec->gpe_bit, ec->command_addr, ec->data_addr)); + ec->gpe, ec->command_addr, ec->data_addr)); /* * Install GPE handler */ - status = acpi_install_gpe_handler(NULL, ec->gpe_bit, + status = acpi_install_gpe_handler(NULL, ec->gpe, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) { return -ENODEV; } - acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, &acpi_ec_space_setup, ec); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec->gpe_bit, - &acpi_ec_gpe_handler); + acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); return -ENODEV; } @@ -814,7 +781,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type) acpi_status status = AE_OK; struct acpi_ec *ec = NULL; - if (!device) return -EINVAL; @@ -826,9 +792,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) if (ACPI_FAILURE(status)) return -ENODEV; - status = - acpi_remove_gpe_handler(NULL, ec->gpe_bit, - &acpi_ec_gpe_handler); + status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); if (ACPI_FAILURE(status)) return -ENODEV; @@ -841,7 +805,7 @@ acpi_fake_ecdt_callback(acpi_handle handle, { acpi_status status; - init_MUTEX(&ec_ecdt->sem); + mutex_init(&ec_ecdt->lock); if (acpi_ec_mode == EC_INTR) { init_waitqueue_head(&ec_ecdt->wait); } @@ -853,16 +817,15 @@ acpi_fake_ecdt_callback(acpi_handle handle, ec_ecdt->uid = -1; acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); - status = - acpi_evaluate_integer(handle, "_GPE", NULL, - &ec_ecdt->gpe_bit); + status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe); if (ACPI_FAILURE(status)) return status; ec_ecdt->global_lock = TRUE; ec_ecdt->handle = handle; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", - ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr)); + ec_ecdt->gpe, ec_ecdt->command_addr, + ec_ecdt->data_addr)); return AE_CTRL_TERMINATE; } @@ -884,12 +847,11 @@ static int __init acpi_ec_fake_ecdt(void) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT")); - ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); + ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec_ecdt) { ret = -ENOMEM; goto error; } - memset(ec_ecdt, 0, sizeof(struct acpi_ec)); status = acpi_get_devices(ACPI_EC_HID, acpi_fake_ecdt_callback, NULL, NULL); @@ -901,7 +863,7 @@ static int __init acpi_ec_fake_ecdt(void) goto error; } return 0; - error: + error: return ret; } @@ -921,30 +883,28 @@ static int __init acpi_ec_get_real_ecdt(void) /* * Generate a temporary ec context to use until the namespace is scanned */ - ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); + ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); if (!ec_ecdt) return -ENOMEM; - memset(ec_ecdt, 0, sizeof(struct acpi_ec)); - init_MUTEX(&ec_ecdt->sem); + mutex_init(&ec_ecdt->lock); if (acpi_ec_mode == EC_INTR) { init_waitqueue_head(&ec_ecdt->wait); } ec_ecdt->command_addr = ecdt_ptr->ec_control.address; ec_ecdt->data_addr = ecdt_ptr->ec_data.address; - ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; + ec_ecdt->gpe = ecdt_ptr->gpe_bit; /* use the GL just to be safe */ ec_ecdt->global_lock = TRUE; ec_ecdt->uid = ecdt_ptr->uid; - status = - acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); + status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); if (ACPI_FAILURE(status)) { goto error; } return 0; - error: + error: ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); kfree(ec_ecdt); ec_ecdt = NULL; @@ -970,14 +930,14 @@ int __init acpi_ec_ecdt_probe(void) /* * Install GPE handler */ - status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit, + status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec_ecdt); if (ACPI_FAILURE(status)) { goto error; } - acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); + acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR); status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, @@ -985,7 +945,7 @@ int __init acpi_ec_ecdt_probe(void) &acpi_ec_space_setup, ec_ecdt); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, &acpi_ec_gpe_handler); goto error; } @@ -1004,7 +964,6 @@ static int __init acpi_ec_init(void) { int result = 0; - if (acpi_disabled) return 0; @@ -1057,7 +1016,8 @@ static int __init acpi_ec_set_intr_mode(char *str) acpi_ec_mode = EC_POLL; } acpi_ec_driver.ops.add = acpi_ec_add; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling")); + printk(KERN_NOTICE PREFIX "%s mode.\n", + intr ? "interrupt" : "polling"); return 1; } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index ee2a10bf907..bf63edc6608 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -331,7 +331,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context) static u32 acpi_ev_global_lock_handler(void *context) { u8 acquired = FALSE; - acpi_status status; /* * Attempt to get the lock diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 3a39c2e8e10..bf90f04f2c6 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -266,10 +266,10 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, walk_state->thread->thread_id) && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) { ACPI_ERROR((AE_INFO, - "Thread %X cannot release Mutex [%4.4s] acquired by thread %X", - (u32) walk_state->thread->thread_id, + "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", + (unsigned long)walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), - (u32) obj_desc->mutex.owner_thread->thread_id)); + (unsigned long)obj_desc->mutex.owner_thread->thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 045c89477e5..f305a826ca2 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -99,8 +99,8 @@ acpi_fan_write_state(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { int result = 0; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_fan *fan = (struct acpi_fan *)m->private; + struct seq_file *m = file->private_data; + struct acpi_fan *fan = m->private; char state_string[12] = { '\0' }; @@ -186,10 +186,9 @@ static int acpi_fan_add(struct acpi_device *device) if (!device) return -EINVAL; - fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL); + fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL); if (!fan) return -ENOMEM; - memset(fan, 0, sizeof(struct acpi_fan)); fan->device = device; strcpy(acpi_device_name(device), "Fan"); @@ -229,7 +228,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - fan = (struct acpi_fan *)acpi_driver_data(device); + fan = acpi_driver_data(device); acpi_fan_remove_fs(device); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a2f46d587d5..8a0324b43e5 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -96,7 +96,7 @@ struct acpi_find_pci_root { static acpi_status do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { - unsigned long *busnr = (unsigned long *)data; + unsigned long *busnr = data; struct acpi_resource_address64 address; if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && @@ -189,8 +189,12 @@ find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv) bus = tmp; if (seg == find->seg && bus == find->bus) + { find->handle = handle; - status = AE_OK; + status = AE_CTRL_TERMINATE; + } + else + status = AE_OK; exit: kfree(buffer.pointer); return status; @@ -217,7 +221,7 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) acpi_status status; struct acpi_device_info *info; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_find_child *find = (struct acpi_find_child *)context; + struct acpi_find_child *find = context; status = acpi_get_object_info(handle, &buffer); if (ACPI_SUCCESS(status)) { diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index 1ba2db67186..8edfb92f7ed 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c @@ -265,8 +265,7 @@ static char *format_result(union acpi_object *object) static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) { - struct acpi_polling_hotkey *poll_hotkey = - (struct acpi_polling_hotkey *)seq->private; + struct acpi_polling_hotkey *poll_hotkey = seq->private; char *buf; @@ -577,7 +576,7 @@ init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, if (ACPI_FAILURE(status)) goto do_fail_zero; key->poll_hotkey.poll_result = - (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); + kmalloc(sizeof(union acpi_object), GFP_KERNEL); if (!key->poll_hotkey.poll_result) goto do_fail_zero; return AE_OK; diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 6342e612c20..8338be0990b 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -309,18 +309,16 @@ static int acpi_ec_hc_add(struct acpi_device *device) return -EINVAL; } - ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL); + ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL); if (!ec_hc) { return -ENOMEM; } - memset(ec_hc, 0, sizeof(struct acpi_ec_hc)); - smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL); + smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL); if (!smbus) { kfree(ec_hc); return -ENOMEM; } - memset(smbus, 0, sizeof(struct acpi_ec_smbus)); ec_hc->handle = device->handle; strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME); @@ -393,7 +391,7 @@ static void __exit acpi_ec_hc_exit(void) struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device) { - return ((struct acpi_ec_hc *)acpi_driver_data(device->parent)); + return acpi_driver_data(device->parent); } EXPORT_SYMBOL(acpi_get_ec_hc); diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 003a9876c96..c6144ca6663 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -3,6 +3,7 @@ * * * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> + * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br> * * 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 @@ -19,10 +20,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define IBM_VERSION "0.12a" +#define IBM_VERSION "0.13" /* * Changelog: + * + * 2006-11-22 0.13 new maintainer + * changelog now lives in git commit history, and will + * not be updated further in-file. * * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels * 2005-03-17 0.11 support for 600e, 770x @@ -77,9 +82,16 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> +#include <linux/string.h> + #include <linux/proc_fs.h> +#include <linux/backlight.h> #include <asm/uaccess.h> +#include <linux/dmi.h> +#include <linux/jiffies.h> +#include <linux/workqueue.h> + #include <acpi/acpi_drivers.h> #include <acpi/acnamesp.h> @@ -88,7 +100,7 @@ #define IBM_FILE "ibm_acpi" #define IBM_URL "http://ibm-acpi.sf.net/" -MODULE_AUTHOR("Borislav Deianov"); +MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); MODULE_DESCRIPTION(IBM_DESC); MODULE_VERSION(IBM_VERSION); MODULE_LICENSE("GPL"); @@ -116,28 +128,6 @@ static acpi_handle root_handle = NULL; static char *object##_path; \ static char *object##_paths[] = { paths } -/* - * The following models are supported to various degrees: - * - * 570, 600e, 600x, 770e, 770x - * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p - * G40, G41 - * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51 - * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43 - * X20, X21, X22, X23, X24, X30, X31, X40 - * - * The following models have no supported features: - * - * 240, 240x, i1400 - * - * Still missing DSDTs for the following models: - * - * A20p, A22e, A22m - * R52 - * S31 - * T43p - */ - IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ "\\_SB.PCI.ISA.EC", /* 570 */ "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ @@ -169,6 +159,7 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ #endif IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ + "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ ); /* A21e, R30, R31 */ @@ -203,7 +194,7 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */ IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ -IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */ +IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ "\\FSPD", /* 600e/x, 770e, 770x */ @@ -216,6 +207,152 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ #define IBM_HKEY_HID "IBM0068" #define IBM_PCI_HID "PNP0A03" +enum thermal_access_mode { + IBMACPI_THERMAL_NONE = 0, /* No thermal support */ + IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ + IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ + IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ + IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ +}; + +#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ +struct ibm_thermal_sensors_struct { + s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; +}; + +/* + * FAN ACCESS MODES + * + * IBMACPI_FAN_RD_ACPI_GFAN: + * ACPI GFAN method: returns fan level + * + * see IBMACPI_FAN_WR_ACPI_SFAN + * EC 0x2f not available if GFAN exists + * + * IBMACPI_FAN_WR_ACPI_SFAN: + * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) + * + * EC 0x2f might be available *for reading*, but never for writing. + * + * IBMACPI_FAN_WR_TPEC: + * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported + * on almost all ThinkPads + * + * Fan speed changes of any sort (including those caused by the + * disengaged mode) are usually done slowly by the firmware as the + * maximum ammount of fan duty cycle change per second seems to be + * limited. + * + * Reading is not available if GFAN exists. + * Writing is not available if SFAN exists. + * + * Bits + * 7 automatic mode engaged; + * (default operation mode of the ThinkPad) + * fan level is ignored in this mode. + * 6 disengage mode (takes precedence over bit 7); + * not available on all thinkpads. May disable + * the tachometer, and speeds up fan to 100% duty-cycle, + * which speeds it up far above the standard RPM + * levels. It is not impossible that it could cause + * hardware damage. + * 5-3 unused in some models. Extra bits for fan level + * in others, but still useless as all values above + * 7 map to the same speed as level 7 in these models. + * 2-0 fan level (0..7 usually) + * 0x00 = stop + * 0x07 = max (set when temperatures critical) + * Some ThinkPads may have other levels, see + * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41) + * + * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at + * boot. Apparently the EC does not intialize it, so unless ACPI DSDT + * does so, its initial value is meaningless (0x07). + * + * For firmware bugs, refer to: + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues + * + * ---- + * + * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): + * Main fan tachometer reading (in RPM) + * + * This register is present on all ThinkPads with a new-style EC, and + * it is known not to be present on the A21m/e, and T22, as there is + * something else in offset 0x84 according to the ACPI DSDT. Other + * ThinkPads from this same time period (and earlier) probably lack the + * tachometer as well. + * + * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare + * was never fixed by IBM to report the EC firmware version string + * probably support the tachometer (like the early X models), so + * detecting it is quite hard. We need more data to know for sure. + * + * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings + * might result. + * + * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this + * register is not invalidated in ThinkPads that disable tachometer + * readings. Thus, the tachometer readings go stale. + * + * For firmware bugs, refer to: + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues + * + * IBMACPI_FAN_WR_ACPI_FANS: + * ThinkPad X31, X40, X41. Not available in the X60. + * + * FANS ACPI handle: takes three arguments: low speed, medium speed, + * high speed. ACPI DSDT seems to map these three speeds to levels + * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH + * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") + * + * The speeds are stored on handles + * (FANA:FAN9), (FANC:FANB), (FANE:FAND). + * + * There are three default speed sets, acessible as handles: + * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H + * + * ACPI DSDT switches which set is in use depending on various + * factors. + * + * IBMACPI_FAN_WR_TPEC is also available and should be used to + * command the fan. The X31/X40/X41 seems to have 8 fan levels, + * but the ACPI tables just mention level 7. + */ + +enum fan_status_access_mode { + IBMACPI_FAN_NONE = 0, /* No fan status or control */ + IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ + IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ +}; + +enum fan_control_access_mode { + IBMACPI_FAN_WR_NONE = 0, /* No fan control */ + IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ + IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ + IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ +}; + +enum fan_control_commands { + IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ + IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ + IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, + * and also watchdog cmd */ +}; + +enum { /* Fan control constants */ + fan_status_offset = 0x2f, /* EC register 0x2f */ + fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) + * 0x84 must be read before 0x85 */ + + IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer + * disengaged */ + IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan + * control */ +}; + +static char *ibm_thinkpad_ec_found = NULL; + struct ibm_struct { char *name; char param[32]; @@ -243,6 +380,8 @@ struct ibm_struct { static struct proc_dir_entry *proc_dir = NULL; +static struct backlight_device *ibm_backlight_device = NULL; + #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") #define strlencmp(a,b) (strncmp((a), (b), strlen(b))) @@ -352,7 +491,7 @@ static char *next_cmd(char **cmds) return start; } -static int driver_init(void) +static int ibm_acpi_driver_init(void) { printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); @@ -581,8 +720,7 @@ static int wan_status(void) { int status; - if (!wan_supported || - !acpi_evalf(hkey_handle, &status, "GWAN", "d")) + if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d")) status = 0; return status; @@ -630,12 +768,15 @@ static int wan_write(char *buf) return 0; } -static int video_supported; -static int video_orig_autosw; +enum video_access_mode { + IBMACPI_VIDEO_NONE = 0, + IBMACPI_VIDEO_570, /* 570 */ + IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */ + IBMACPI_VIDEO_NEW, /* all others */ +}; -#define VIDEO_570 1 -#define VIDEO_770 2 -#define VIDEO_NEW 3 +static enum video_access_mode video_supported; +static int video_orig_autosw; static int video_init(void) { @@ -647,16 +788,16 @@ static int video_init(void) if (!vid_handle) /* video switching not supported on R30, R31 */ - video_supported = 0; + video_supported = IBMACPI_VIDEO_NONE; else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) /* 570 */ - video_supported = VIDEO_570; + video_supported = IBMACPI_VIDEO_570; else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) /* 600e/x, 770e, 770x */ - video_supported = VIDEO_770; + video_supported = IBMACPI_VIDEO_770; else /* all others */ - video_supported = VIDEO_NEW; + video_supported = IBMACPI_VIDEO_NEW; return 0; } @@ -666,15 +807,15 @@ static int video_status(void) int status = 0; int i; - if (video_supported == VIDEO_570) { + if (video_supported == IBMACPI_VIDEO_570) { if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) status = i & 3; - } else if (video_supported == VIDEO_770) { + } else if (video_supported == IBMACPI_VIDEO_770) { if (acpi_evalf(NULL, &i, "\\VCDL", "d")) status |= 0x01 * i; if (acpi_evalf(NULL, &i, "\\VCDC", "d")) status |= 0x02 * i; - } else if (video_supported == VIDEO_NEW) { + } else if (video_supported == IBMACPI_VIDEO_NEW) { acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); if (acpi_evalf(NULL, &i, "\\VCDC", "d")) status |= 0x02 * i; @@ -693,9 +834,10 @@ static int video_autosw(void) { int autosw = 0; - if (video_supported == VIDEO_570) + if (video_supported == IBMACPI_VIDEO_570) acpi_evalf(vid_handle, &autosw, "SWIT", "d"); - else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW) + else if (video_supported == IBMACPI_VIDEO_770 || + video_supported == IBMACPI_VIDEO_NEW) acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); return autosw & 1; @@ -715,12 +857,12 @@ static int video_read(char *p) len += sprintf(p + len, "status:\t\tsupported\n"); len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); - if (video_supported == VIDEO_NEW) + if (video_supported == IBMACPI_VIDEO_NEW) len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); - if (video_supported == VIDEO_NEW) + if (video_supported == IBMACPI_VIDEO_NEW) len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); @@ -735,7 +877,7 @@ static int video_switch(void) if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) return -EIO; - ret = video_supported == VIDEO_570 ? + ret = video_supported == IBMACPI_VIDEO_570 ? acpi_evalf(ec_handle, NULL, "_Q16", "v") : acpi_evalf(vid_handle, NULL, "VSWT", "v"); acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); @@ -745,9 +887,9 @@ static int video_switch(void) static int video_expand(void) { - if (video_supported == VIDEO_570) + if (video_supported == IBMACPI_VIDEO_570) return acpi_evalf(ec_handle, NULL, "_Q17", "v"); - else if (video_supported == VIDEO_770) + else if (video_supported == IBMACPI_VIDEO_770) return acpi_evalf(vid_handle, NULL, "VEXP", "v"); else return acpi_evalf(NULL, NULL, "\\VEXP", "v"); @@ -757,10 +899,10 @@ static int video_switch2(int status) { int ret; - if (video_supported == VIDEO_570) { + if (video_supported == IBMACPI_VIDEO_570) { ret = acpi_evalf(NULL, NULL, "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); - } else if (video_supported == VIDEO_770) { + } else if (video_supported == IBMACPI_VIDEO_770) { int autosw = video_autosw(); if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) return -EIO; @@ -796,10 +938,10 @@ static int video_write(char *buf) enable |= 0x02; } else if (strlencmp(cmd, "crt_disable") == 0) { disable |= 0x02; - } else if (video_supported == VIDEO_NEW && + } else if (video_supported == IBMACPI_VIDEO_NEW && strlencmp(cmd, "dvi_enable") == 0) { enable |= 0x08; - } else if (video_supported == VIDEO_NEW && + } else if (video_supported == IBMACPI_VIDEO_NEW && strlencmp(cmd, "dvi_disable") == 0) { disable |= 0x08; } else if (strlencmp(cmd, "auto_enable") == 0) { @@ -907,6 +1049,7 @@ static int _sta(acpi_handle handle) return status; } + #ifdef CONFIG_ACPI_IBM_DOCK #define dock_docked() (_sta(dock_handle) & 1) @@ -1094,26 +1237,28 @@ static int cmos_write(char *buf) return 0; } -static int led_supported; - -#define LED_570 1 -#define LED_OLD 2 -#define LED_NEW 3 +enum led_access_mode { + IBMACPI_LED_NONE = 0, + IBMACPI_LED_570, /* 570 */ + IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + IBMACPI_LED_NEW, /* all others */ +}; +static enum led_access_mode led_supported; static int led_init(void) { if (!led_handle) /* led not supported on R30, R31 */ - led_supported = 0; + led_supported = IBMACPI_LED_NONE; else if (strlencmp(led_path, "SLED") == 0) /* 570 */ - led_supported = LED_570; + led_supported = IBMACPI_LED_570; else if (strlencmp(led_path, "SYSL") == 0) /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - led_supported = LED_OLD; + led_supported = IBMACPI_LED_OLD; else /* all others */ - led_supported = LED_NEW; + led_supported = IBMACPI_LED_NEW; return 0; } @@ -1130,7 +1275,7 @@ static int led_read(char *p) } len += sprintf(p + len, "status:\t\tsupported\n"); - if (led_supported == LED_570) { + if (led_supported == IBMACPI_LED_570) { /* 570 */ int i, status; for (i = 0; i < 8; i++) { @@ -1179,13 +1324,13 @@ static int led_write(char *buf) } else return -EINVAL; - if (led_supported == LED_570) { + if (led_supported == IBMACPI_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 == LED_OLD) { + } else if (led_supported == IBMACPI_LED_OLD) { /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ led = 1 << led; ret = ec_write(EC_HLMS, led); @@ -1272,50 +1417,142 @@ static int acpi_ec_write(int i, u8 v) return 1; } -static int thermal_tmp_supported; -static int thermal_updt_supported; +static enum thermal_access_mode thermal_read_mode; static int thermal_init(void) { - /* temperatures not supported on 570, G4x, R30, R31, R32 */ - thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); + u8 t, ta1, ta2; + int i; + int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); + + if (ibm_thinkpad_ec_found && experimental) { + /* + * Direct EC access mode: sensors at registers + * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for + * non-implemented, thermal sensors return 0x80 when + * not available + */ - /* 600e/x, 770e, 770x */ - thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv"); + ta1 = ta2 = 0; + for (i = 0; i < 8; i++) { + if (likely(acpi_ec_read(0x78 + i, &t))) { + ta1 |= t; + } else { + ta1 = 0; + break; + } + if (likely(acpi_ec_read(0xC0 + i, &t))) { + ta2 |= t; + } else { + ta1 = 0; + break; + } + } + if (ta1 == 0) { + /* This is sheer paranoia, but we handle it anyway */ + if (acpi_tmp7) { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "falling back to ACPI TMPx access mode\n"); + thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; + } else { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "disabling thermal sensors access\n"); + thermal_read_mode = IBMACPI_THERMAL_NONE; + } + } else { + thermal_read_mode = + (ta2 != 0) ? + IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8; + } + } else if (acpi_tmp7) { + if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { + /* 600e/x, 770e, 770x */ + thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; + } else { + /* Standard ACPI TMPx access, max 8 sensors */ + thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; + } + } else { + /* temperatures not supported on 570, G4x, R30, R31, R32 */ + thermal_read_mode = IBMACPI_THERMAL_NONE; + } return 0; } -static int thermal_read(char *p) +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) { - int len = 0; + int i, t; + s8 tmp; + char tmpi[] = "TMPi"; - if (!thermal_tmp_supported) - len += sprintf(p + len, "temperatures:\tnot supported\n"); - else { - int i, t; - char tmpi[] = "TMPi"; - s8 tmp[8]; + if (!s) + return -EINVAL; - if (thermal_updt_supported) - if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) + switch (thermal_read_mode) { +#if IBMACPI_MAX_THERMAL_SENSORS >= 16 + case IBMACPI_THERMAL_TPEC_16: + for (i = 0; i < 8; i++) { + if (!acpi_ec_read(0xC0 + i, &tmp)) + return -EIO; + s->temp[i + 8] = tmp * 1000; + } + /* fallthrough */ +#endif + case IBMACPI_THERMAL_TPEC_8: + for (i = 0; i < 8; i++) { + if (!acpi_ec_read(0x78 + i, &tmp)) return -EIO; + s->temp[i] = tmp * 1000; + } + return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8; + case IBMACPI_THERMAL_ACPI_UPDT: + if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) + return -EIO; for (i = 0; i < 8; i++) { tmpi[3] = '0' + i; if (!acpi_evalf(ec_handle, &t, tmpi, "d")) return -EIO; - if (thermal_updt_supported) - tmp[i] = (t - 2732 + 5) / 10; - else - tmp[i] = t; + s->temp[i] = (t - 2732) * 100; } + return 8; - len += sprintf(p + len, - "temperatures:\t%d %d %d %d %d %d %d %d\n", - tmp[0], tmp[1], tmp[2], tmp[3], - tmp[4], tmp[5], tmp[6], tmp[7]); + case IBMACPI_THERMAL_ACPI_TMP07: + for (i = 0; i < 8; i++) { + tmpi[3] = '0' + i; + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) + return -EIO; + s->temp[i] = t * 1000; + } + return 8; + + case IBMACPI_THERMAL_NONE: + default: + return 0; } +} + +static int thermal_read(char *p) +{ + int len = 0; + int n, i; + struct ibm_thermal_sensors_struct t; + + n = thermal_get_sensors(&t); + if (unlikely(n < 0)) + return n; + + len += sprintf(p + len, "temperatures:\t"); + + if (n > 0) { + for (i = 0; i < (n - 1); i++) + len += sprintf(p + len, "%d ", t.temp[i] / 1000); + len += sprintf(p + len, "%d\n", t.temp[i] / 1000); + } else + len += sprintf(p + len, "not supported\n"); return len; } @@ -1381,12 +1618,23 @@ static int ecdump_write(char *buf) static int brightness_offset = 0x31; +static int brightness_get(struct backlight_device *bd) +{ + u8 level; + if (!acpi_ec_read(brightness_offset, &level)) + return -EIO; + + level &= 0x7; + + return level; +} + static int brightness_read(char *p) { int len = 0; - u8 level; + int level; - if (!acpi_ec_read(brightness_offset, &level)) { + if ((level = brightness_get(NULL)) < 0) { len += sprintf(p + len, "level:\t\tunreadable\n"); } else { len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); @@ -1401,16 +1649,34 @@ static int brightness_read(char *p) #define BRIGHTNESS_UP 4 #define BRIGHTNESS_DOWN 5 -static int brightness_write(char *buf) +static int brightness_set(int value) { int cmos_cmd, inc, i; - u8 level; + int current_value = brightness_get(NULL); + + value &= 7; + + cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; + inc = value > current_value ? 1 : -1; + for (i = current_value; i != value; i += inc) { + if (!cmos_eval(cmos_cmd)) + return -EIO; + if (!acpi_ec_write(brightness_offset, i + inc)) + return -EIO; + } + + return 0; +} + +static int brightness_write(char *buf) +{ + int level; int new_level; char *cmd; while ((cmd = next_cmd(&buf))) { - if (!acpi_ec_read(brightness_offset, &level)) - return -EIO; + if ((level = brightness_get(NULL)) < 0) + return level; level &= 7; if (strlencmp(cmd, "up") == 0) { @@ -1423,19 +1689,44 @@ static int brightness_write(char *buf) } else return -EINVAL; - cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; - inc = new_level > level ? 1 : -1; - for (i = level; i != new_level; i += inc) { - if (!cmos_eval(cmos_cmd)) - return -EIO; - if (!acpi_ec_write(brightness_offset, i + inc)) - return -EIO; - } + brightness_set(new_level); + } + + return 0; +} + +static int brightness_update_status(struct backlight_device *bd) +{ + return brightness_set(bd->props->brightness); +} + +static struct backlight_properties ibm_backlight_data = { + .owner = THIS_MODULE, + .get_brightness = brightness_get, + .update_status = brightness_update_status, + .max_brightness = 7, +}; + +static int brightness_init(void) +{ + ibm_backlight_device = backlight_device_register("ibm", NULL, NULL, + &ibm_backlight_data); + if (IS_ERR(ibm_backlight_device)) { + printk(IBM_ERR "Could not register backlight device\n"); + return PTR_ERR(ibm_backlight_device); } return 0; } +static void brightness_exit(void) +{ + if (ibm_backlight_device) { + backlight_device_unregister(ibm_backlight_device); + ibm_backlight_device = NULL; + } +} + static int volume_offset = 0x30; static int volume_read(char *p) @@ -1522,90 +1813,486 @@ static int volume_write(char *buf) return 0; } -static int fan_status_offset = 0x2f; -static int fan_rpm_offset = 0x84; +static enum fan_status_access_mode fan_status_access_mode; +static enum fan_control_access_mode fan_control_access_mode; +static enum fan_control_commands fan_control_commands; -static int fan_read(char *p) +static int fan_control_status_known; +static u8 fan_control_initial_status; + +static void fan_watchdog_fire(struct work_struct *ignored); +static int fan_watchdog_maxinterval; +static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); + +static int fan_init(void) { - int len = 0; - int s; - u8 lo, hi, status; + fan_status_access_mode = IBMACPI_FAN_NONE; + fan_control_access_mode = IBMACPI_FAN_WR_NONE; + fan_control_commands = 0; + fan_control_status_known = 1; + fan_watchdog_maxinterval = 0; if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ - if (!acpi_evalf(gfan_handle, &s, NULL, "d")) - return -EIO; + fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN; + } else { + /* all other ThinkPads: note that even old-style + * ThinkPad ECs supports the fan control register */ + if (likely(acpi_ec_read(fan_status_offset, + &fan_control_initial_status))) { + fan_status_access_mode = IBMACPI_FAN_RD_TPEC; + + /* In some ThinkPads, neither the EC nor the ACPI + * DSDT initialize the fan status, and it ends up + * being set to 0x07 when it *could* be either + * 0x07 or 0x80. + * + * Enable for TP-1Y (T43), TP-78 (R51e), + * TP-76 (R52), TP-70 (T43, R52), which are known + * to be buggy. */ + if (fan_control_initial_status == 0x07 && + ibm_thinkpad_ec_found && + ((ibm_thinkpad_ec_found[0] == '1' && + ibm_thinkpad_ec_found[1] == 'Y') || + (ibm_thinkpad_ec_found[0] == '7' && + (ibm_thinkpad_ec_found[1] == '6' || + ibm_thinkpad_ec_found[1] == '8' || + ibm_thinkpad_ec_found[1] == '0')) + )) { + printk(IBM_NOTICE + "fan_init: initial fan status is " + "unknown, assuming it is in auto " + "mode\n"); + fan_control_status_known = 0; + } + } else { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "fan status and control unavailable\n"); + return 0; + } + } - len += sprintf(p + len, "level:\t\t%d\n", s); + if (sfan_handle) { + /* 570, 770x-JL */ + fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN; + fan_control_commands |= + IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE; } else { + if (!gfan_handle) { + /* gfan without sfan means no fan control */ + /* all other models implement TP EC 0x2f control */ + + if (fans_handle) { + /* X31, X40, X41 */ + fan_control_access_mode = + IBMACPI_FAN_WR_ACPI_FANS; + fan_control_commands |= + IBMACPI_FAN_CMD_SPEED | + IBMACPI_FAN_CMD_LEVEL | + IBMACPI_FAN_CMD_ENABLE; + } else { + fan_control_access_mode = IBMACPI_FAN_WR_TPEC; + fan_control_commands |= + IBMACPI_FAN_CMD_LEVEL | + IBMACPI_FAN_CMD_ENABLE; + } + } + } + + return 0; +} + +static int fan_get_status(u8 *status) +{ + u8 s; + + /* TODO: + * Add IBMACPI_FAN_RD_ACPI_FANS ? */ + + switch (fan_status_access_mode) { + case IBMACPI_FAN_RD_ACPI_GFAN: + /* 570, 600e/x, 770e, 770x */ + + if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) + return -EIO; + + if (likely(status)) + *status = s & 0x07; + + break; + + case IBMACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ - if (!acpi_ec_read(fan_status_offset, &status)) - len += sprintf(p + len, "status:\t\tunreadable\n"); - else - len += sprintf(p + len, "status:\t\t%s\n", - enabled(status, 7)); + if (unlikely(!acpi_ec_read(fan_status_offset, &s))) + return -EIO; - if (!acpi_ec_read(fan_rpm_offset, &lo) || - !acpi_ec_read(fan_rpm_offset + 1, &hi)) - len += sprintf(p + len, "speed:\t\tunreadable\n"); - else - len += sprintf(p + len, "speed:\t\t%d\n", - (hi << 8) + lo); + if (likely(status)) + *status = s; + + break; + + default: + return -ENXIO; } - if (sfan_handle) - /* 570, 770x-JL */ - len += sprintf(p + len, "commands:\tlevel <level>" - " (<level> is 0-7)\n"); - if (!gfan_handle) + return 0; +} + +static int fan_get_speed(unsigned int *speed) +{ + u8 hi, lo; + + switch (fan_status_access_mode) { + case IBMACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ - len += sprintf(p + len, "commands:\tenable, disable\n"); - if (fans_handle) - /* X31, X40 */ + if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || + !acpi_ec_read(fan_rpm_offset + 1, &hi))) + return -EIO; + + if (likely(speed)) + *speed = (hi << 8) | lo; + + break; + + default: + return -ENXIO; + } + + return 0; +} + +static void fan_exit(void) +{ + cancel_delayed_work(&fan_watchdog_task); + flush_scheduled_work(); +} + +static void fan_watchdog_reset(void) +{ + static int fan_watchdog_active = 0; + + if (fan_watchdog_active) + cancel_delayed_work(&fan_watchdog_task); + + if (fan_watchdog_maxinterval > 0) { + fan_watchdog_active = 1; + if (!schedule_delayed_work(&fan_watchdog_task, + msecs_to_jiffies(fan_watchdog_maxinterval + * 1000))) { + printk(IBM_ERR "failed to schedule the fan watchdog, " + "watchdog will not trigger\n"); + } + } else + fan_watchdog_active = 0; +} + +static int fan_read(char *p) +{ + int len = 0; + int rc; + u8 status; + unsigned int speed = 0; + + switch (fan_status_access_mode) { + case IBMACPI_FAN_RD_ACPI_GFAN: + /* 570, 600e/x, 770e, 770x */ + if ((rc = fan_get_status(&status)) < 0) + return rc; + + len += sprintf(p + len, "status:\t\t%s\n" + "level:\t\t%d\n", + (status != 0) ? "enabled" : "disabled", status); + break; + + case IBMACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if ((rc = fan_get_status(&status)) < 0) + return rc; + + if (unlikely(!fan_control_status_known)) { + if (status != fan_control_initial_status) + fan_control_status_known = 1; + else + /* Return most likely status. In fact, it + * might be the only possible status */ + status = IBMACPI_FAN_EC_AUTO; + } + + len += sprintf(p + len, "status:\t\t%s\n", + (status != 0) ? "enabled" : "disabled"); + + /* No ThinkPad boots on disengaged mode, we can safely + * assume the tachometer is online if fan control status + * was unknown */ + if ((rc = fan_get_speed(&speed)) < 0) + return rc; + + len += sprintf(p + len, "speed:\t\t%d\n", speed); + + if (status & IBMACPI_FAN_EC_DISENGAGED) + /* Disengaged mode takes precedence */ + len += sprintf(p + len, "level:\t\tdisengaged\n"); + else if (status & IBMACPI_FAN_EC_AUTO) + len += sprintf(p + len, "level:\t\tauto\n"); + else + len += sprintf(p + len, "level:\t\t%d\n", status); + break; + + case IBMACPI_FAN_NONE: + default: + len += sprintf(p + len, "status:\t\tnot supported\n"); + } + + if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) { + len += sprintf(p + len, "commands:\tlevel <level>"); + + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_SFAN: + len += sprintf(p + len, " (<level> is 0-7)\n"); + break; + + default: + len += sprintf(p + len, " (<level> is 0-7, " + "auto, disengaged)\n"); + break; + } + } + + if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) + len += sprintf(p + len, "commands:\tenable, disable\n" + "commands:\twatchdog <timeout> (<timeout> is 0 (off), " + "1-120 (seconds))\n"); + + if (fan_control_commands & IBMACPI_FAN_CMD_SPEED) len += sprintf(p + len, "commands:\tspeed <speed>" " (<speed> is 0-65535)\n"); return len; } -static int fan_write(char *buf) +static int fan_set_level(int level) { - char *cmd; - int level, speed; - - while ((cmd = next_cmd(&buf))) { - if (sfan_handle && - sscanf(cmd, "level %d", &level) == 1 && - level >= 0 && level <= 7) { - /* 570, 770x-JL */ + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_SFAN: + if (level >= 0 && level <= 7) { if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) return -EIO; - } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) { - /* all except 570, 600e/x, 770e, 770x */ - if (!acpi_ec_write(fan_status_offset, 0x80)) - return -EIO; - } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) { - /* all except 570, 600e/x, 770e, 770x */ - if (!acpi_ec_write(fan_status_offset, 0x00)) - return -EIO; - } else if (fans_handle && - sscanf(cmd, "speed %d", &speed) == 1 && - speed >= 0 && speed <= 65535) { - /* X31, X40 */ + } else + return -EINVAL; + break; + + case IBMACPI_FAN_WR_ACPI_FANS: + case IBMACPI_FAN_WR_TPEC: + if ((level != IBMACPI_FAN_EC_AUTO) && + (level != IBMACPI_FAN_EC_DISENGAGED) && + ((level < 0) || (level > 7))) + return -EINVAL; + + if (!acpi_ec_write(fan_status_offset, level)) + return -EIO; + else + fan_control_status_known = 1; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_set_enable(void) +{ + u8 s; + int rc; + + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_FANS: + case IBMACPI_FAN_WR_TPEC: + if ((rc = fan_get_status(&s)) < 0) + return rc; + + /* Don't go out of emergency fan mode */ + if (s != 7) + s = IBMACPI_FAN_EC_AUTO; + + if (!acpi_ec_write(fan_status_offset, s)) + return -EIO; + else + fan_control_status_known = 1; + break; + + case IBMACPI_FAN_WR_ACPI_SFAN: + if ((rc = fan_get_status(&s)) < 0) + return rc; + + s &= 0x07; + + /* Set fan to at least level 4 */ + if (s < 4) + s = 4; + + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) + return -EIO; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_set_disable(void) +{ + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_FANS: + case IBMACPI_FAN_WR_TPEC: + if (!acpi_ec_write(fan_status_offset, 0x00)) + return -EIO; + else + fan_control_status_known = 1; + break; + + case IBMACPI_FAN_WR_ACPI_SFAN: + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) + return -EIO; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_set_speed(int speed) +{ + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_FANS: + if (speed >= 0 && speed <= 65535) { if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", speed, speed, speed)) return -EIO; } else return -EINVAL; - } + break; + default: + return -ENXIO; + } return 0; } +static int fan_write_cmd_level(const char *cmd, int *rc) +{ + int level; + + if (strlencmp(cmd, "level auto") == 0) + level = IBMACPI_FAN_EC_AUTO; + else if (strlencmp(cmd, "level disengaged") == 0) + level = IBMACPI_FAN_EC_DISENGAGED; + else if (sscanf(cmd, "level %d", &level) != 1) + return 0; + + if ((*rc = fan_set_level(level)) == -ENXIO) + printk(IBM_ERR "level command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_enable(const char *cmd, int *rc) +{ + if (strlencmp(cmd, "enable") != 0) + return 0; + + if ((*rc = fan_set_enable()) == -ENXIO) + printk(IBM_ERR "enable command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_disable(const char *cmd, int *rc) +{ + if (strlencmp(cmd, "disable") != 0) + return 0; + + if ((*rc = fan_set_disable()) == -ENXIO) + printk(IBM_ERR "disable command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_speed(const char *cmd, int *rc) +{ + int speed; + + /* TODO: + * Support speed <low> <medium> <high> ? */ + + if (sscanf(cmd, "speed %d", &speed) != 1) + return 0; + + if ((*rc = fan_set_speed(speed)) == -ENXIO) + printk(IBM_ERR "speed command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_watchdog(const char *cmd, int *rc) +{ + int interval; + + if (sscanf(cmd, "watchdog %d", &interval) != 1) + return 0; + + if (interval < 0 || interval > 120) + *rc = -EINVAL; + else + fan_watchdog_maxinterval = interval; + + return 1; +} + +static int fan_write(char *buf) +{ + char *cmd; + int rc = 0; + + while (!rc && (cmd = next_cmd(&buf))) { + if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) && + fan_write_cmd_level(cmd, &rc)) && + !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) && + (fan_write_cmd_enable(cmd, &rc) || + fan_write_cmd_disable(cmd, &rc) || + fan_write_cmd_watchdog(cmd, &rc))) && + !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) && + fan_write_cmd_speed(cmd, &rc)) + ) + rc = -EINVAL; + else if (!rc) + fan_watchdog_reset(); + } + + return rc; +} + +static void fan_watchdog_fire(struct work_struct *ignored) +{ + printk(IBM_NOTICE "fan watchdog: enabling fan\n"); + if (fan_set_enable()) { + printk(IBM_ERR "fan watchdog: error while enabling fan\n"); + /* reschedule for later */ + fan_watchdog_reset(); + } +} + static struct ibm_struct ibms[] = { { .name = "driver", - .init = driver_init, + .init = ibm_acpi_driver_init, .read = driver_read, }, { @@ -1702,6 +2389,8 @@ static struct ibm_struct ibms[] = { .name = "brightness", .read = brightness_read, .write = brightness_write, + .init = brightness_init, + .exit = brightness_exit, }, { .name = "volume", @@ -1712,6 +2401,8 @@ static struct ibm_struct ibms[] = { .name = "fan", .read = fan_read, .write = fan_write, + .init = fan_init, + .exit = fan_exit, .experimental = 1, }, }; @@ -1719,7 +2410,7 @@ static struct ibm_struct ibms[] = { static int dispatch_read(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct ibm_struct *ibm = (struct ibm_struct *)data; + struct ibm_struct *ibm = data; int len; if (!ibm || !ibm->read) @@ -1744,7 +2435,7 @@ static int dispatch_read(char *page, char **start, off_t off, int count, static int dispatch_write(struct file *file, const char __user * userbuf, unsigned long count, void *data) { - struct ibm_struct *ibm = (struct ibm_struct *)data; + struct ibm_struct *ibm = data; char *kernbuf; int ret; @@ -1773,7 +2464,7 @@ static int dispatch_write(struct file *file, const char __user * userbuf, static void dispatch_notify(acpi_handle handle, u32 event, void *data) { - struct ibm_struct *ibm = (struct ibm_struct *)data; + struct ibm_struct *ibm = data; if (!ibm || !ibm->notify) return; @@ -1805,7 +2496,7 @@ static int __init setup_notify(struct ibm_struct *ibm) ibm->name, status); return -ENODEV; } - + ibm->notify_installed = 1; return 0; } @@ -1818,14 +2509,13 @@ static int __init register_driver(struct ibm_struct *ibm) { int ret; - ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL); + ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); if (!ibm->driver) { printk(IBM_ERR "kmalloc(ibm->driver) failed\n"); return -1; } - memset(ibm->driver, 0, sizeof(struct acpi_driver)); - sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); + sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name); ibm->driver->ids = ibm->hid; ibm->driver->ops.add = &ibm_device_add; @@ -1882,7 +2572,6 @@ static int __init ibm_init(struct ibm_struct *ibm) ret = setup_notify(ibm); if (ret < 0) return ret; - ibm->notify_installed = 1; } return 0; @@ -1971,6 +2660,33 @@ static void acpi_ibm_exit(void) ibm_exit(&ibms[i]); remove_proc_entry(IBM_DIR, acpi_root_dir); + + if (ibm_thinkpad_ec_found) + kfree(ibm_thinkpad_ec_found); +} + +static char* __init check_dmi_for_ec(void) +{ + struct dmi_device *dev = NULL; + char ec_fw_string[18]; + + /* + * ThinkPad T23 or newer, A31 or newer, R50e or newer, + * X32 or newer, all Z series; Some models must have an + * up-to-date BIOS or they will not be detected. + * + * See http://thinkwiki.org/wiki/List_of_DMI_IDs + */ + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + if (sscanf(dev->name, + "IBM ThinkPad Embedded Controller -[%17c", + ec_fw_string) == 1) { + ec_fw_string[sizeof(ec_fw_string) - 1] = 0; + ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; + return kstrdup(ec_fw_string, GFP_KERNEL); + } + } + return NULL; } static int __init acpi_ibm_init(void) @@ -1992,6 +2708,12 @@ static int __init acpi_ibm_init(void) return -ENODEV; } + /* Models with newer firmware report the EC in DMI */ + ibm_thinkpad_ec_found = check_dmi_for_ec(); + if (ibm_thinkpad_ec_found) + printk(IBM_INFO "ThinkPad EC firmware %s\n", + ibm_thinkpad_ec_found); + /* these handles are not required */ IBM_HANDLE_INIT(vid); IBM_HANDLE_INIT(vid2); diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index a163e1d3708..a18b1c22312 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -50,6 +50,50 @@ ACPI_MODULE_NAME("nsxfobj") /******************************************************************************* * + * FUNCTION: acpi_get_id + * + * PARAMETERS: Handle - Handle of object whose id is desired + * ret_id - Where the id will be placed + * + * RETURN: Status + * + * DESCRIPTION: This routine returns the owner id associated with a handle + * + ******************************************************************************/ +acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) +{ + struct acpi_namespace_node *node; + acpi_status status; + + /* Parameter Validation */ + + if (!ret_id) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node(handle); + if (!node) { + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return (AE_BAD_PARAMETER); + } + + *ret_id = node->owner_id; + + status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return (status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_id) + +/******************************************************************************* + * * FUNCTION: acpi_get_type * * PARAMETERS: Handle - Handle of object whose type is desired diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index e5e448edca4..bd96a704592 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -248,7 +248,7 @@ int acpi_get_pxm(acpi_handle h) handle = phandle; status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm); if (ACPI_SUCCESS(status)) - return (int)pxm; + return pxm; status = acpi_get_parent(handle, &phandle); } while (ACPI_SUCCESS(status)); return -1; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 02b30ae6a68..57ae1e5cde0 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -568,6 +568,7 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ static void acpi_os_execute_deferred(struct work_struct *work) { struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); + if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); return; @@ -1031,7 +1032,7 @@ acpi_status acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) { *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL); - if (cache == NULL) + if (*cache == NULL) return AE_ERROR; else return AE_OK; @@ -1051,7 +1052,7 @@ acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) acpi_status acpi_os_purge_cache(acpi_cache_t * cache) { - (void)kmem_cache_shrink(cache); + kmem_cache_shrink(cache); return (AE_OK); } diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 1e2ae6e7a7e..55f57a61c55 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -122,19 +122,17 @@ int acpi_pci_bind(struct acpi_device *device) if (!device || !device->parent) return -EINVAL; - pathname = kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); + pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); if (!pathname) return -ENOMEM; - memset(pathname, 0, ACPI_PATHNAME_MAX); buffer.length = ACPI_PATHNAME_MAX; buffer.pointer = pathname; - data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); + data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); if (!data) { kfree(pathname); return -ENOMEM; } - memset(data, 0, sizeof(struct acpi_pci_data)); acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", @@ -281,10 +279,9 @@ int acpi_pci_unbind(struct acpi_device *device) if (!device || !device->parent) return -EINVAL; - pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); + pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); if (!pathname) return -ENOMEM; - memset(pathname, 0, ACPI_PATHNAME_MAX); buffer.length = ACPI_PATHNAME_MAX; buffer.pointer = pathname; @@ -331,11 +328,9 @@ acpi_pci_bind_root(struct acpi_device *device, char *pathname = NULL; struct acpi_buffer buffer = { 0, NULL }; - - pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); + pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); if (!pathname) return -ENOMEM; - memset(pathname, 0, ACPI_PATHNAME_MAX); buffer.length = ACPI_PATHNAME_MAX; buffer.pointer = pathname; @@ -345,12 +340,11 @@ acpi_pci_bind_root(struct acpi_device *device, return -EINVAL; } - data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); + data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); if (!data) { kfree(pathname); return -ENOMEM; } - memset(data, 0, sizeof(struct acpi_pci_data)); data->id = *id; data->bus = bus; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index feda0341f5a..fe7d007833a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -89,10 +89,9 @@ acpi_pci_irq_add_entry(acpi_handle handle, if (!prt) return -EINVAL; - entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); + entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); if (!entry) return -ENOMEM; - memset(entry, 0, sizeof(struct acpi_prt_entry)); entry->id.segment = segment; entry->id.bus = bus; @@ -161,10 +160,9 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) static int first_time = 1; - pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); + pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); if (!pathname) return -ENOMEM; - memset(pathname, 0, ACPI_PATHNAME_MAX); if (first_time) { acpi_prt.count = 0; @@ -198,11 +196,10 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) return -ENODEV; } - prt = kmalloc(buffer.length, GFP_KERNEL); + prt = kzalloc(buffer.length, GFP_KERNEL); if (!prt) { return -ENOMEM; } - memset(prt, 0, buffer.length); buffer.pointer = prt; status = acpi_get_irq_routing_table(handle, &buffer); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index d53bd9878ca..481e633bbf4 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -103,7 +103,7 @@ DEFINE_MUTEX(acpi_link_lock); static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, void *context) { - struct acpi_pci_link *link = (struct acpi_pci_link *)context; + struct acpi_pci_link *link = context; u32 i = 0; @@ -307,11 +307,10 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) if (!link || !irq) return -EINVAL; - resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); + resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); if (!resource) return -ENOMEM; - memset(resource, 0, sizeof(*resource) + 1); buffer.length = sizeof(*resource) + 1; buffer.pointer = resource; @@ -613,7 +612,7 @@ acpi_pci_link_allocate_irq(acpi_handle handle, return -1; } - link = (struct acpi_pci_link *)acpi_driver_data(device); + link = acpi_driver_data(device); if (!link) { printk(KERN_ERR PREFIX "Invalid link context\n"); return -1; @@ -668,7 +667,7 @@ int acpi_pci_link_free_irq(acpi_handle handle) return -1; } - link = (struct acpi_pci_link *)acpi_driver_data(device); + link = acpi_driver_data(device); if (!link) { printk(KERN_ERR PREFIX "Invalid link context\n"); return -1; @@ -718,10 +717,9 @@ static int acpi_pci_link_add(struct acpi_device *device) if (!device) return -EINVAL; - link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); + link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); if (!link) return -ENOMEM; - memset(link, 0, sizeof(struct acpi_pci_link)); link->device = device; strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); @@ -808,7 +806,7 @@ static int acpi_pci_link_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - link = (struct acpi_pci_link *)acpi_driver_data(device); + link = acpi_driver_data(device); mutex_lock(&acpi_link_lock); list_del(&link->node); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0984a1ee24e..a860efa2c56 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -98,11 +98,12 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) struct acpi_pci_driver **pptr = &sub_driver; while (*pptr) { - if (*pptr != driver) - continue; - *pptr = (*pptr)->next; - break; + if (*pptr == driver) + break; + pptr = &(*pptr)->next; } + BUG_ON(!*pptr); + *pptr = (*pptr)->next; if (!driver->remove) return; @@ -119,7 +120,7 @@ EXPORT_SYMBOL(acpi_pci_unregister_driver); static acpi_status get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { - int *busnr = (int *)data; + int *busnr = data; struct acpi_resource_address64 address; if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && @@ -164,10 +165,9 @@ static int acpi_pci_root_add(struct acpi_device *device) if (!device) return -EINVAL; - root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); + root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) return -ENOMEM; - memset(root, 0, sizeof(struct acpi_pci_root)); INIT_LIST_HEAD(&root->node); root->device = device; @@ -331,7 +331,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - root = (struct acpi_pci_root *)acpi_driver_data(device); + root = acpi_driver_data(device); kfree(root); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index fe67a8af520..0ba7dfbbb2e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -108,7 +108,7 @@ acpi_power_get_context(acpi_handle handle, return result; } - *resource = (struct acpi_power_resource *)acpi_driver_data(device); + *resource = acpi_driver_data(device); if (!resource) return -ENODEV; @@ -442,7 +442,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) struct acpi_power_resource *resource = NULL; - resource = (struct acpi_power_resource *)seq->private; + resource = seq->private; if (!resource) goto end; @@ -532,10 +532,9 @@ static int acpi_power_add(struct acpi_device *device) if (!device) return -EINVAL; - resource = kmalloc(sizeof(struct acpi_power_resource), GFP_KERNEL); + resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL); if (!resource) return -ENOMEM; - memset(resource, 0, sizeof(struct acpi_power_resource)); resource->device = device; strcpy(resource->name, device->pnp.bus_id); @@ -590,7 +589,7 @@ static int acpi_power_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - resource = (struct acpi_power_resource *)acpi_driver_data(device); + resource = acpi_driver_data(device); acpi_power_remove_fs(device); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 1908e0d2022..5f9496d59ed 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -277,7 +277,7 @@ static struct proc_dir_entry *acpi_processor_dir = NULL; static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset) { - struct acpi_processor *pr = (struct acpi_processor *)seq->private; + struct acpi_processor *pr = seq->private; if (!pr) @@ -476,9 +476,6 @@ static int acpi_processor_get_info(struct acpi_processor *pr) if (cpu_index == -1) { if (ACPI_FAILURE (acpi_processor_hotadd_init(pr->handle, &pr->id))) { - printk(KERN_ERR PREFIX - "Getting cpuindex for acpiid 0x%x\n", - pr->acpi_id); return -ENODEV; } } @@ -542,12 +539,12 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) * Don't trust it blindly */ if (processor_device_array[pr->id] != NULL && - processor_device_array[pr->id] != (void *)device) { + processor_device_array[pr->id] != device) { printk(KERN_WARNING "BIOS reported wrong ACPI id" "for the processor\n"); return -ENODEV; } - processor_device_array[pr->id] = (void *)device; + processor_device_array[pr->id] = device; processors[pr->id] = pr; @@ -578,7 +575,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_processor *pr = (struct acpi_processor *)data; + struct acpi_processor *pr = data; struct acpi_device *device = NULL; @@ -615,10 +612,9 @@ static int acpi_processor_add(struct acpi_device *device) if (!device) return -EINVAL; - pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL); + pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return -ENOMEM; - memset(pr, 0, sizeof(struct acpi_processor)); pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); @@ -637,7 +633,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - pr = (struct acpi_processor *)acpi_driver_data(device); + pr = acpi_driver_data(device); if (pr->id >= NR_CPUS) { kfree(pr); @@ -901,13 +897,13 @@ static int __init acpi_processor_init(void) acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); if (!acpi_processor_dir) - return 0; + return -ENOMEM; acpi_processor_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_processor_driver); if (result < 0) { remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); - return 0; + return result; } acpi_processor_install_hotplug_notify(); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 65b3f056ad8..3f30af21574 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -211,7 +211,11 @@ acpi_processor_power_activate(struct acpi_processor *pr, static void acpi_safe_halt(void) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); if (!need_resched()) safe_halt(); current_thread_info()->status |= TS_POLLING; @@ -345,7 +349,11 @@ static void acpi_processor_idle(void) */ if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); if (need_resched()) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); @@ -673,7 +681,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) return -ENODEV; } - cst = (union acpi_object *)buffer.pointer; + cst = buffer.pointer; /* There must be at least 2 elements */ if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) { @@ -702,14 +710,14 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) memset(&cx, 0, sizeof(cx)); - element = (union acpi_object *)&(cst->package.elements[i]); + element = &(cst->package.elements[i]); if (element->type != ACPI_TYPE_PACKAGE) continue; if (element->package.count != 4) continue; - obj = (union acpi_object *)&(element->package.elements[0]); + obj = &(element->package.elements[0]); if (obj->type != ACPI_TYPE_BUFFER) continue; @@ -721,7 +729,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) continue; /* There should be an easy way to extract an integer... */ - obj = (union acpi_object *)&(element->package.elements[1]); + obj = &(element->package.elements[1]); if (obj->type != ACPI_TYPE_INTEGER) continue; @@ -754,13 +762,13 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) } } - obj = (union acpi_object *)&(element->package.elements[2]); + obj = &(element->package.elements[2]); if (obj->type != ACPI_TYPE_INTEGER) continue; cx.latency = obj->integer.value; - obj = (union acpi_object *)&(element->package.elements[3]); + obj = &(element->package.elements[3]); if (obj->type != ACPI_TYPE_INTEGER) continue; @@ -1029,7 +1037,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) { - struct acpi_processor *pr = (struct acpi_processor *)seq->private; + struct acpi_processor *pr = seq->private; unsigned int i; diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 6fd174a3714..cbb6f0814ce 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -236,7 +236,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) return -ENODEV; } - pss = (union acpi_object *)buffer.pointer; + pss = buffer.pointer; if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { printk(KERN_ERR PREFIX "Invalid _PSS data\n"); result = -EFAULT; @@ -322,10 +322,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) if (result) return result; - result = acpi_processor_get_platform_limit(pr); - if (result) - return result; - return 0; } @@ -410,7 +406,7 @@ static struct file_operations acpi_processor_perf_fops = { static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset) { - struct acpi_processor *pr = (struct acpi_processor *)seq->private; + struct acpi_processor *pr = seq->private; int i; @@ -451,8 +447,8 @@ acpi_processor_write_performance(struct file *file, size_t count, loff_t * data) { int result = 0; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_processor *pr = (struct acpi_processor *)m->private; + struct seq_file *m = file->private_data; + struct acpi_processor *pr = m->private; struct acpi_processor_performance *perf; char state_string[12] = { '\0' }; unsigned int new_state = 0; @@ -551,7 +547,7 @@ static int acpi_processor_get_psd(struct acpi_processor *pr) return -ENODEV; } - psd = (union acpi_object *) buffer.pointer; + psd = buffer.pointer; if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; @@ -736,10 +732,6 @@ int acpi_processor_preregister_performance( } err_ret: - if (retval) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n")); - } - for_each_possible_cpu(i) { pr = processors[i]; if (!pr || !pr->performance) diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index ef5e0f6efdb..40fecd67ad8 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -208,7 +208,7 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type) if (result) return result; - pr = (struct acpi_processor *)acpi_driver_data(device); + pr = acpi_driver_data(device); if (!pr) return -ENODEV; @@ -348,8 +348,8 @@ static ssize_t acpi_processor_write_limit(struct file * file, size_t count, loff_t * data) { int result = 0; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_processor *pr = (struct acpi_processor *)m->private; + struct seq_file *m = file->private_data; + struct acpi_processor *pr = m->private; char limit_string[25] = { '\0' }; int px = 0; int tx = 0; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index d044ec519db..0ec7dcde006 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -259,7 +259,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) static int acpi_processor_throttling_seq_show(struct seq_file *seq, void *offset) { - struct acpi_processor *pr = (struct acpi_processor *)seq->private; + struct acpi_processor *pr = seq->private; int i = 0; int result = 0; @@ -307,8 +307,8 @@ static ssize_t acpi_processor_write_throttling(struct file * file, size_t count, loff_t * data) { int result = 0; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_processor *pr = (struct acpi_processor *)m->private; + struct seq_file *m = file->private_data; + struct acpi_processor *pr = m->private; char state_string[12] = { '\0' }; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 8908a975e57..f58fc7447ab 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -923,7 +923,7 @@ static struct proc_dir_entry *acpi_battery_dir = NULL; static int acpi_battery_read_info(struct seq_file *seq, void *offset) { - struct acpi_battery *battery = (struct acpi_battery *)seq->private; + struct acpi_battery *battery = seq->private; int cscale; int result = 0; @@ -1076,7 +1076,7 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) { - struct acpi_battery *battery = (struct acpi_battery *)seq->private; + struct acpi_battery *battery = seq->private; int result = 0; int cscale; @@ -1125,8 +1125,8 @@ static ssize_t acpi_battery_write_alarm(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { - struct seq_file *seq = (struct seq_file *)file->private_data; - struct acpi_battery *battery = (struct acpi_battery *)seq->private; + struct seq_file *seq = file->private_data; + struct acpi_battery *battery = seq->private; char alarm_string[12] = { '\0' }; int result, old_alarm, new_alarm; @@ -1160,14 +1160,14 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_battery_set_alarm() failed\n")); - (void)acpi_battery_set_alarm(battery, old_alarm); + acpi_battery_set_alarm(battery, old_alarm); goto end; } result = acpi_battery_get_alarm(battery); if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_battery_get_alarm() failed\n")); - (void)acpi_battery_set_alarm(battery, old_alarm); + acpi_battery_set_alarm(battery, old_alarm); goto end; } @@ -1217,7 +1217,7 @@ static struct proc_dir_entry *acpi_ac_dir = NULL; static int acpi_ac_read_state(struct seq_file *seq, void *offset) { - struct acpi_sbs *sbs = (struct acpi_sbs *)seq->private; + struct acpi_sbs *sbs = seq->private; int result; if (sbs->zombie) { @@ -1302,7 +1302,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) battery->init_state = 1; } - (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); + sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); result = acpi_sbs_generic_add_fs(&battery->battery_entry, acpi_battery_dir, @@ -1485,7 +1485,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type) } if (old_battery_present != new_battery_present) { - (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); + sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); result = acpi_sbs_generate_event(sbs->device, ACPI_SBS_BATTERY_NOTIFY_STATUS, new_battery_present, @@ -1498,7 +1498,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type) } } if (old_remaining_capacity != battery->state.remaining_capacity) { - (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); + sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); result = acpi_sbs_generate_event(sbs->device, ACPI_SBS_BATTERY_NOTIFY_STATUS, new_battery_present, @@ -1576,12 +1576,11 @@ static int acpi_sbs_add(struct acpi_device *device) int id, cnt; acpi_status status = AE_OK; - sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL); + sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); if (!sbs) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n")); return -ENOMEM; } - memset(sbs, 0, sizeof(struct acpi_sbs)); cnt = 0; while (cnt < 10) { @@ -1659,7 +1658,7 @@ static int acpi_sbs_add(struct acpi_device *device) init_timer(&sbs->update_timer); if (update_mode == QUEUE_UPDATE_MODE) { status = acpi_os_execute(OSL_GPE_HANDLER, - acpi_sbs_update_queue, (void *)sbs); + acpi_sbs_update_queue, sbs); if (status != AE_OK) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_os_execute() failed\n")); @@ -1685,7 +1684,7 @@ static int acpi_sbs_add(struct acpi_device *device) int acpi_sbs_remove(struct acpi_device *device, int type) { - struct acpi_sbs *sbs = NULL; + struct acpi_sbs *sbs; int id; if (!device) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 698a1540e30..283d87522c5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -984,12 +984,11 @@ acpi_add_single_object(struct acpi_device **child, if (!child) return -EINVAL; - device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL); + device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); if (!device) { printk(KERN_ERR PREFIX "Memory allocation error\n"); return -ENOMEM; } - memset(device, 0, sizeof(struct acpi_device)); device->handle = handle; device->parent = parent; diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c index af1dbabaf0b..fab8f2694f0 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/sleep/wakeup.c @@ -183,11 +183,11 @@ late_initcall(acpi_wakeup_device_init); #endif /* - * Disable all wakeup GPEs before power off. - * + * Disable all wakeup GPEs before entering requested sleep state. + * @sleep_state: ACPI state * Since acpi_enter_sleep_state() will disable all * RUNTIME GPEs, we simply mark all GPES that - * are not enabled for wakeup from S5 as RUNTIME. + * are not enabled for wakeup from requested state as RUNTIME. */ void acpi_gpe_sleep_prepare(u32 sleep_state) { diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index bfb3bfcf9e9..ffa30c9fccb 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -228,7 +228,7 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header) static int acpi_table_compute_checksum(void *table_pointer, unsigned long length) { - u8 *p = (u8 *) table_pointer; + u8 *p = table_pointer; unsigned long remains = length; unsigned long sum = 0; diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 7767987be15..5ba9303293a 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -123,7 +123,6 @@ acpi_status acpi_load_tables(void) ACPI_EXPORT_SYMBOL(acpi_load_tables) -#ifdef ACPI_FUTURE_USAGE /******************************************************************************* * * FUNCTION: acpi_load_table @@ -221,6 +220,59 @@ ACPI_EXPORT_SYMBOL(acpi_load_table) /******************************************************************************* * + * FUNCTION: acpi_unload_table_id + * + * PARAMETERS: table_type - Type of table to be unloaded + * id - Owner ID of the table to be removed. + * + * RETURN: Status + * + * DESCRIPTION: This routine is used to force the unload of a table (by id) + * + ******************************************************************************/ +acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id) +{ + struct acpi_table_desc *table_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_unload_table); + + /* Parameter validation */ + if (table_type > ACPI_TABLE_ID_MAX) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + /* Find table from the requested type list */ + table_desc = acpi_gbl_table_lists[table_type].next; + while (table_desc && table_desc->owner_id != id) + table_desc = table_desc->next; + + if (!table_desc) + return_ACPI_STATUS(AE_NOT_EXIST); + + /* + * Delete all namespace objects owned by this table. Note that these + * objects can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not + * simply a position within the hierarchy + */ + acpi_ns_delete_namespace_by_owner(table_desc->owner_id); + + status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + + (void)acpi_tb_uninstall_table(table_desc); + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + + return_ACPI_STATUS(AE_OK); +} + +ACPI_EXPORT_SYMBOL(acpi_unload_table_id) + +#ifdef ACPI_FUTURE_USAGE +/******************************************************************************* + * * FUNCTION: acpi_unload_table * * PARAMETERS: table_type - Type of table to be unloaded diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 5753d06b786..40ddb4dd963 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -663,7 +663,7 @@ static void acpi_thermal_run(unsigned long data) static void acpi_thermal_check(void *data) { int result = 0; - struct acpi_thermal *tz = (struct acpi_thermal *)data; + struct acpi_thermal *tz = data; unsigned long sleep_time = 0; int i = 0; struct acpi_thermal_state state; @@ -778,7 +778,7 @@ static struct proc_dir_entry *acpi_thermal_dir; static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset) { - struct acpi_thermal *tz = (struct acpi_thermal *)seq->private; + struct acpi_thermal *tz = seq->private; if (!tz) @@ -813,7 +813,7 @@ static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file) static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset) { int result = 0; - struct acpi_thermal *tz = (struct acpi_thermal *)seq->private; + struct acpi_thermal *tz = seq->private; if (!tz) @@ -837,7 +837,7 @@ static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file) static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset) { - struct acpi_thermal *tz = (struct acpi_thermal *)seq->private; + struct acpi_thermal *tz = seq->private; int i = 0; int j = 0; @@ -893,8 +893,8 @@ acpi_thermal_write_trip_points(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_thermal *tz = (struct acpi_thermal *)m->private; + struct seq_file *m = file->private_data; + struct acpi_thermal *tz = m->private; char *limit_string; int num, critical, hot, passive; @@ -902,12 +902,10 @@ acpi_thermal_write_trip_points(struct file *file, int i = 0; - limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL); + limit_string = kzalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL); if (!limit_string) return -ENOMEM; - memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN); - active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL); if (!active) { kfree(limit_string); @@ -953,7 +951,7 @@ acpi_thermal_write_trip_points(struct file *file, static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset) { - struct acpi_thermal *tz = (struct acpi_thermal *)seq->private; + struct acpi_thermal *tz = seq->private; if (!tz) @@ -984,8 +982,8 @@ acpi_thermal_write_cooling_mode(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_thermal *tz = (struct acpi_thermal *)m->private; + struct seq_file *m = file->private_data; + struct acpi_thermal *tz = m->private; int result = 0; char mode_string[12] = { '\0' }; @@ -1014,7 +1012,7 @@ acpi_thermal_write_cooling_mode(struct file *file, static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset) { - struct acpi_thermal *tz = (struct acpi_thermal *)seq->private; + struct acpi_thermal *tz = seq->private; if (!tz) @@ -1043,8 +1041,8 @@ acpi_thermal_write_polling(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_thermal *tz = (struct acpi_thermal *)m->private; + struct seq_file *m = file->private_data; + struct acpi_thermal *tz = m->private; int result = 0; char polling_string[12] = { '\0' }; int seconds = 0; @@ -1170,7 +1168,7 @@ static int acpi_thermal_remove_fs(struct acpi_device *device) static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_thermal *tz = (struct acpi_thermal *)data; + struct acpi_thermal *tz = data; struct acpi_device *device = NULL; @@ -1271,10 +1269,9 @@ static int acpi_thermal_add(struct acpi_device *device) if (!device) return -EINVAL; - tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL); + tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL); if (!tz) return -ENOMEM; - memset(tz, 0, sizeof(struct acpi_thermal)); tz->device = device; strcpy(tz->name, device->pnp.bus_id); @@ -1324,7 +1321,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - tz = (struct acpi_thermal *)acpi_driver_data(device); + tz = acpi_driver_data(device); /* avoid timer adding new defer task */ tz->zombie = 1; @@ -1364,7 +1361,7 @@ static int acpi_thermal_resume(struct acpi_device *device, int state) if (!device || !acpi_driver_data(device)) return -EINVAL; - tz = (struct acpi_thermal *)acpi_driver_data(device); + tz = acpi_driver_data(device); acpi_thermal_get_temperature(tz); diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index 7fe0b7ae973..d9b651ffcdc 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -41,6 +41,8 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/proc_fs.h> +#include <linux/backlight.h> + #include <asm/uaccess.h> #include <acpi/acpi_drivers.h> @@ -210,6 +212,7 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result) } static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; +static struct backlight_device *toshiba_backlight_device; static int force_fan; static int last_key_event; static int key_event_valid; @@ -271,14 +274,23 @@ dispatch_write(struct file *file, const char __user * buffer, return result; } -static char *read_lcd(char *p) +static int get_lcd(struct backlight_device *bd) { u32 hci_result; u32 value; hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); if (hci_result == HCI_SUCCESS) { - value = value >> HCI_LCD_BRIGHTNESS_SHIFT; + return (value >> HCI_LCD_BRIGHTNESS_SHIFT); + } else + return -EFAULT; +} + +static char *read_lcd(char *p) +{ + int value = get_lcd(NULL); + + if (value >= 0) { p += sprintf(p, "brightness: %d\n", value); p += sprintf(p, "brightness_levels: %d\n", HCI_LCD_BRIGHTNESS_LEVELS); @@ -289,22 +301,37 @@ static char *read_lcd(char *p) return p; } +static int set_lcd(int value) +{ + u32 hci_result; + + value = value << HCI_LCD_BRIGHTNESS_SHIFT; + hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); + if (hci_result != HCI_SUCCESS) + return -EFAULT; + + return 0; +} + +static int set_lcd_status(struct backlight_device *bd) +{ + return set_lcd(bd->props->brightness); +} + static unsigned long write_lcd(const char *buffer, unsigned long count) { int value; - u32 hci_result; + int ret; if (sscanf(buffer, " brightness : %i", &value) == 1 && value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { - value = value << HCI_LCD_BRIGHTNESS_SHIFT; - hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); - if (hci_result != HCI_SUCCESS) - return -EFAULT; + ret = set_lcd(value); + if (ret == 0) + ret = count; } else { - return -EINVAL; + ret = -EINVAL; } - - return count; + return ret; } static char *read_video(char *p) @@ -506,6 +533,26 @@ static acpi_status __exit remove_device(void) return AE_OK; } +static struct backlight_properties toshiba_backlight_data = { + .owner = THIS_MODULE, + .get_brightness = get_lcd, + .update_status = set_lcd_status, + .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1, +}; + +static void __exit toshiba_acpi_exit(void) +{ + if (toshiba_backlight_device) + backlight_device_unregister(toshiba_backlight_device); + + remove_device(); + + if (toshiba_proc_dir) + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + + return; +} + static int __init toshiba_acpi_init(void) { acpi_status status = AE_OK; @@ -546,17 +593,16 @@ static int __init toshiba_acpi_init(void) remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); } - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - -static void __exit toshiba_acpi_exit(void) -{ - remove_device(); - - if (toshiba_proc_dir) - remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + toshiba_backlight_device = backlight_device_register("toshiba",NULL, + NULL, + &toshiba_backlight_data); + if (IS_ERR(toshiba_backlight_device)) { + printk(KERN_ERR "Could not register toshiba backlight device\n"); + toshiba_backlight_device = NULL; + toshiba_acpi_exit(); + } - return; + return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; } module_init(toshiba_acpi_init); diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index bb1eaf9aa65..9e9054e155c 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -180,8 +180,9 @@ acpi_ut_debug_print(u32 requested_debug_level, if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf - ("\n**** Context Switch from TID %X to TID %X ****\n\n", - (u32) acpi_gbl_prev_thread_id, (u32) thread_id); + ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", + (unsigned long) acpi_gbl_prev_thread_id, + (unsigned long) thread_id); } acpi_gbl_prev_thread_id = thread_id; diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index c39062a047c..180e73ceb6e 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -243,23 +243,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) #endif ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %X attempting to acquire Mutex [%s]\n", - (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); + "Thread %lX attempting to acquire Mutex [%s]\n", + (unsigned long) this_thread_id, + acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %X acquired Mutex [%s]\n", - (u32) this_thread_id, + "Thread %lX acquired Mutex [%s]\n", + (unsigned long) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; } else { ACPI_EXCEPTION((AE_INFO, status, - "Thread %X could not acquire Mutex [%X]", - (u32) this_thread_id, mutex_id)); + "Thread %lX could not acquire Mutex [%X]", + (unsigned long) this_thread_id, mutex_id)); } return (status); @@ -285,7 +286,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) this_thread_id = acpi_os_get_thread_id(); ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id, + "Thread %lX releasing Mutex [%s]\n", + (unsigned long) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index d0d84c43a9d..68a809fa7b1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -83,7 +83,7 @@ acpi_extract_package(union acpi_object *package, return AE_BAD_DATA; } - format_string = (char *)format->pointer; + format_string = format->pointer; /* * Calculate size_required. @@ -262,11 +262,10 @@ acpi_evaluate_integer(acpi_handle handle, if (!data) return AE_BAD_PARAMETER; - element = kmalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); + element = kzalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); if (!element) return AE_NO_MEMORY; - memset(element, 0, sizeof(union acpi_object)); buffer.length = sizeof(union acpi_object); buffer.pointer = element; status = acpi_evaluate_object(handle, pathname, arguments, &buffer); @@ -321,12 +320,11 @@ acpi_evaluate_string(acpi_handle handle, return AE_BAD_DATA; } - *data = kmalloc(element->string.length + 1, GFP_KERNEL); + *data = kzalloc(element->string.length + 1, GFP_KERNEL); if (!data) { printk(KERN_ERR PREFIX "Memory allocation\n"); return -ENOMEM; } - memset(*data, 0, element->string.length + 1); memcpy(*data, element->string.pointer, element->string.length); @@ -361,7 +359,7 @@ acpi_evaluate_reference(acpi_handle handle, if (ACPI_FAILURE(status)) goto end; - package = (union acpi_object *)buffer.pointer; + package = buffer.pointer; if ((buffer.length == 0) || !package) { printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n", diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 56666a98247..3d54680d033 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -3,6 +3,7 @@ * * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org> + * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -47,11 +48,11 @@ #define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83 #define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84 -#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x82 -#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x83 -#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x84 -#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x85 -#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x86 +#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85 +#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 +#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 +#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) @@ -386,7 +387,7 @@ acpi_video_device_EDID(struct acpi_video_device *device, if (ACPI_FAILURE(status)) return -ENODEV; - obj = (union acpi_object *)buffer.pointer; + obj = buffer.pointer; if (obj && obj->type == ACPI_TYPE_BUFFER) *edid = obj; @@ -532,11 +533,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) int count = 0; union acpi_object *o; - br = kmalloc(sizeof(*br), GFP_KERNEL); + br = kzalloc(sizeof(*br), GFP_KERNEL); if (!br) { printk(KERN_ERR "can't allocate memory\n"); } else { - memset(br, 0, sizeof(*br)); br->levels = kmalloc(obj->package.count * sizeof *(br->levels), GFP_KERNEL); if (!br->levels) @@ -654,8 +654,7 @@ static struct proc_dir_entry *acpi_video_dir; static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_device *dev = - (struct acpi_video_device *)seq->private; + struct acpi_video_device *dev = seq->private; if (!dev) @@ -688,8 +687,7 @@ acpi_video_device_info_open_fs(struct inode *inode, struct file *file) static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset) { int status; - struct acpi_video_device *dev = - (struct acpi_video_device *)seq->private; + struct acpi_video_device *dev = seq->private; unsigned long state; @@ -727,8 +725,8 @@ acpi_video_device_write_state(struct file *file, size_t count, loff_t * data) { int status; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_video_device *dev = (struct acpi_video_device *)m->private; + struct seq_file *m = file->private_data; + struct acpi_video_device *dev = m->private; char str[12] = { 0 }; u32 state = 0; @@ -754,8 +752,7 @@ acpi_video_device_write_state(struct file *file, static int acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_device *dev = - (struct acpi_video_device *)seq->private; + struct acpi_video_device *dev = seq->private; int i; @@ -784,8 +781,8 @@ acpi_video_device_write_brightness(struct file *file, const char __user * buffer, size_t count, loff_t * data) { - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_video_device *dev = (struct acpi_video_device *)m->private; + struct seq_file *m = file->private_data; + struct acpi_video_device *dev = m->private; char str[4] = { 0 }; unsigned int level = 0; int i; @@ -817,8 +814,7 @@ acpi_video_device_write_brightness(struct file *file, static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_device *dev = - (struct acpi_video_device *)seq->private; + struct acpi_video_device *dev = seq->private; int status; int i; union acpi_object *edid = NULL; @@ -866,7 +862,7 @@ static int acpi_video_device_add_fs(struct acpi_device *device) if (!device) return -ENODEV; - vid_dev = (struct acpi_video_device *)acpi_driver_data(device); + vid_dev = acpi_driver_data(device); if (!vid_dev) return -ENODEV; @@ -931,7 +927,7 @@ static int acpi_video_device_remove_fs(struct acpi_device *device) { struct acpi_video_device *vid_dev; - vid_dev = (struct acpi_video_device *)acpi_driver_data(device); + vid_dev = acpi_driver_data(device); if (!vid_dev || !vid_dev->video || !vid_dev->video->dir) return -ENODEV; @@ -950,7 +946,7 @@ static int acpi_video_device_remove_fs(struct acpi_device *device) /* video bus */ static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private; + struct acpi_video_bus *video = seq->private; if (!video) @@ -975,7 +971,7 @@ static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file) static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private; + struct acpi_video_bus *video = seq->private; if (!video) @@ -995,7 +991,7 @@ static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file) static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private; + struct acpi_video_bus *video = seq->private; unsigned long options; int status; @@ -1033,7 +1029,7 @@ acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file) static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private; + struct acpi_video_bus *video = seq->private; int status; unsigned long id; @@ -1054,7 +1050,7 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset) static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset) { - struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private; + struct acpi_video_bus *video = seq->private; seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting); @@ -1079,8 +1075,8 @@ acpi_video_bus_write_POST(struct file *file, size_t count, loff_t * data) { int status; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_video_bus *video = (struct acpi_video_bus *)m->private; + struct seq_file *m = file->private_data; + struct acpi_video_bus *video = m->private; char str[12] = { 0 }; unsigned long opt, options; @@ -1119,8 +1115,8 @@ acpi_video_bus_write_DOS(struct file *file, size_t count, loff_t * data) { int status; - struct seq_file *m = (struct seq_file *)file->private_data; - struct acpi_video_bus *video = (struct acpi_video_bus *)m->private; + struct seq_file *m = file->private_data; + struct acpi_video_bus *video = m->private; char str[12] = { 0 }; unsigned long opt; @@ -1150,7 +1146,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) struct acpi_video_bus *video; - video = (struct acpi_video_bus *)acpi_driver_data(device); + video = acpi_driver_data(device); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), @@ -1226,7 +1222,7 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device) struct acpi_video_bus *video; - video = (struct acpi_video_bus *)acpi_driver_data(device); + video = acpi_driver_data(device); if (acpi_device_dir(device)) { remove_proc_entry("info", acpi_device_dir(device)); @@ -1263,12 +1259,10 @@ acpi_video_bus_get_one_device(struct acpi_device *device, acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); if (ACPI_SUCCESS(status)) { - data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL); + data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); if (!data) return -ENOMEM; - memset(data, 0, sizeof(struct acpi_video_device)); - strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); acpi_driver_data(device) = data; @@ -1403,7 +1397,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) return status; } - dod = (union acpi_object *)buffer.pointer; + dod = buffer.pointer; if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) { ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data")); status = -EFAULT; @@ -1426,7 +1420,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) count = 0; for (i = 0; i < dod->package.count; i++) { - obj = (union acpi_object *)&dod->package.elements[i]; + obj = &dod->package.elements[i]; if (obj->type != ACPI_TYPE_INTEGER) { printk(KERN_ERR PREFIX "Invalid _DOD data\n"); @@ -1509,8 +1503,34 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event) { - /*Fix me */ - return level_current; + int min, max, min_above, max_below, i, l; + max = max_below = 0; + min = min_above = 255; + for (i = 0; i < device->brightness->count; i++) { + l = device->brightness->levels[i]; + if (l < min) + min = l; + if (l > max) + max = l; + if (l < min_above && l > level_current) + min_above = l; + if (l > max_below && l < level_current) + max_below = l; + } + + switch (event) { + case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: + return (level_current < max) ? min_above : min; + case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: + return (level_current < max) ? min_above : max; + case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: + return (level_current > min) ? max_below : min; + case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: + case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: + return 0; + default: + return level_current; + } } static void @@ -1612,7 +1632,7 @@ static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_video_bus *video = (struct acpi_video_bus *)data; + struct acpi_video_bus *video = data; struct acpi_device *device = NULL; printk("video bus notify\n"); @@ -1654,12 +1674,9 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data) static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_video_device *video_device = - (struct acpi_video_device *)data; + struct acpi_video_device *video_device = data; struct acpi_device *device = NULL; - - printk("video device notify\n"); if (!video_device) return; @@ -1696,10 +1713,9 @@ static int acpi_video_bus_add(struct acpi_device *device) if (!device) return -EINVAL; - video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); + video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); if (!video) return -ENOMEM; - memset(video, 0, sizeof(struct acpi_video_bus)); video->device = device; strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); @@ -1757,7 +1773,7 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - video = (struct acpi_video_bus *)acpi_driver_data(device); + video = acpi_driver_data(device); acpi_video_bus_stop_devices(video); diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index b34e0a958d0..1c94b43d2c9 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -19,6 +19,10 @@ config ATA if ATA +config ATA_NONSTANDARD + bool + default n + config SATA_AHCI tristate "AHCI SATA support" depends on PCI @@ -381,7 +385,7 @@ config PATA_OPTI If unsure, say N. config PATA_OPTIDMA - tristate "OPTI FireStar PATA support (Veyr Experimental)" + tristate "OPTI FireStar PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL help This option enables DMA/PIO support for the later OPTi diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index dbae6d97104..48616c6fee9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -75,6 +75,7 @@ enum { AHCI_CMD_CLR_BUSY = (1 << 10), RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ + RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, @@ -202,6 +203,10 @@ struct ahci_port_priv { dma_addr_t cmd_tbl_dma; void *rx_fis; dma_addr_t rx_fis_dma; + /* for NCQ spurious interrupt analysis */ + int ncq_saw_spurious_sdb_cnt; + unsigned int ncq_saw_d2h:1; + unsigned int ncq_saw_dmas:1; }; static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); @@ -361,7 +366,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ - { PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */ + { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ @@ -402,6 +407,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ + { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ @@ -578,35 +591,18 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap) { u32 cmd, scontrol; - cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; - - if (cap & HOST_CAP_SSC) { - /* enable transitions to slumber mode */ - scontrol = readl(port_mmio + PORT_SCR_CTL); - if ((scontrol & 0x0f00) > 0x100) { - scontrol &= ~0xf00; - writel(scontrol, port_mmio + PORT_SCR_CTL); - } - - /* put device into slumber mode */ - writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD); - - /* wait for the transition to complete */ - ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER, - PORT_CMD_ICC_SLUMBER, 1, 50); - } + if (!(cap & HOST_CAP_SSS)) + return; - /* put device into listen mode */ - if (cap & HOST_CAP_SSS) { - /* first set PxSCTL.DET to 0 */ - scontrol = readl(port_mmio + PORT_SCR_CTL); - scontrol &= ~0xf; - writel(scontrol, port_mmio + PORT_SCR_CTL); + /* put device into listen mode, first set PxSCTL.DET to 0 */ + scontrol = readl(port_mmio + PORT_SCR_CTL); + scontrol &= ~0xf; + writel(scontrol, port_mmio + PORT_SCR_CTL); - /* then set PxCMD.SUD to 0 */ - cmd &= ~PORT_CMD_SPIN_UP; - writel(cmd, port_mmio + PORT_CMD); - } + /* then set PxCMD.SUD to 0 */ + cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; + cmd &= ~PORT_CMD_SPIN_UP; + writel(cmd, port_mmio + PORT_CMD); } static void ahci_init_port(void __iomem *port_mmio, u32 cap, @@ -907,7 +903,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(ap->device, &tf); - tf.command = 0xff; + tf.command = 0x80; ata_tf_to_fis(&tf, d2h_fis, 0); rc = sata_std_hardreset(ap, class); @@ -1118,8 +1114,9 @@ static void ahci_host_intr(struct ata_port *ap) void __iomem *mmio = ap->host->mmio_base; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); struct ata_eh_info *ehi = &ap->eh_info; + struct ahci_port_priv *pp = ap->private_data; u32 status, qc_active; - int rc; + int rc, known_irq = 0; status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); @@ -1146,17 +1143,53 @@ static void ahci_host_intr(struct ata_port *ap) /* hmmm... a spurious interupt */ - /* some devices send D2H reg with I bit set during NCQ command phase */ - if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS)) + /* if !NCQ, ignore. No modern ATA device has broken HSM + * implementation for non-NCQ commands. + */ + if (!ap->sactive) return; - /* ignore interim PIO setup fis interrupts */ - if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) - return; + if (status & PORT_IRQ_D2H_REG_FIS) { + if (!pp->ncq_saw_d2h) + ata_port_printk(ap, KERN_INFO, + "D2H reg with I during NCQ, " + "this message won't be printed again\n"); + pp->ncq_saw_d2h = 1; + known_irq = 1; + } + + if (status & PORT_IRQ_DMAS_FIS) { + if (!pp->ncq_saw_dmas) + ata_port_printk(ap, KERN_INFO, + "DMAS FIS during NCQ, " + "this message won't be printed again\n"); + pp->ncq_saw_dmas = 1; + known_irq = 1; + } + + if (status & PORT_IRQ_SDB_FIS && + pp->ncq_saw_spurious_sdb_cnt < 10) { + /* SDB FIS containing spurious completions might be + * dangerous, we need to know more about them. Print + * more of it. + */ + const u32 *f = pp->rx_fis + RX_FIS_SDB; + + ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ " + "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n", + readl(port_mmio + PORT_CMD_ISSUE), + readl(port_mmio + PORT_SCR_ACT), + le32_to_cpu(f[0]), le32_to_cpu(f[1]), + pp->ncq_saw_spurious_sdb_cnt < 10 ? + "" : ", shutting up"); + + pp->ncq_saw_spurious_sdb_cnt++; + known_irq = 1; + } - if (ata_ratelimit()) + if (!known_irq) ata_port_printk(ap, KERN_INFO, "spurious interrupt " - "(irq_stat 0x%x active_tag %d sactive 0x%x)\n", + "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", status, ap->active_tag, ap->sactive); } @@ -1249,7 +1282,7 @@ static void ahci_thaw(struct ata_port *ap) /* clear IRQ */ tmp = readl(port_mmio + PORT_IRQ_STAT); writel(tmp, port_mmio + PORT_IRQ_STAT); - writel(1 << ap->id, mmio + HOST_IRQ_STAT); + writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); /* turn IRQ back on */ writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 908751d27e7..24af56081b5 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -64,6 +64,7 @@ static void generic_error_handler(struct ata_port *ap) /** * generic_set_mode - mode setting * @ap: interface to set up + * @unused: returned device on error * * Use a non standard set_mode function. We don't want to be tuned. * The BIOS configured everything. Our job is not to fiddle. We @@ -71,7 +72,7 @@ static void generic_error_handler(struct ata_port *ap) * and respect them. */ -static void generic_set_mode(struct ata_port *ap) +static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) { int dma_enabled = 0; int i; @@ -82,7 +83,7 @@ static void generic_set_mode(struct ata_port *ap) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; - if (ata_dev_enabled(dev)) { + if (ata_dev_ready(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; dev->dma_mode = XFER_MW_DMA_0; @@ -99,6 +100,7 @@ static void generic_set_mode(struct ata_port *ap) } } } + return 0; } static struct scsi_host_template generic_sht = { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0d51d13b16b..667acd28336 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1037,7 +1037,7 @@ static unsigned int ata_id_xfermask(const u16 *id) * the PIO timing number for the maximum. Turn it into * a mask. */ - u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF; + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; if (mode < 5) /* Valid PIO range */ pio_mask = (2 << mode) - 1; else @@ -1250,6 +1250,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, ata_sg_init(qc, sg, n_elem); qc->nsect = buflen / ATA_SECT_SIZE; + qc->nbytes = buflen; } qc->private_data = &wait; @@ -2431,18 +2432,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) int i, rc = 0, used_dma = 0, found = 0; /* has private set_mode? */ - if (ap->ops->set_mode) { - /* FIXME: make ->set_mode handle no device case and - * return error code and failing device on failure. - */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - if (ata_dev_ready(&ap->device[i])) { - ap->ops->set_mode(ap); - break; - } - } - return 0; - } + if (ap->ops->set_mode) + return ap->ops->set_mode(ap, r_failed_dev); /* step 1: calculate xfer_mask */ for (i = 0; i < ATA_MAX_DEVICES; i++) { diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 08ad44b3e48..748435807d6 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1796,7 +1796,7 @@ static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) *r_failed_dev = dev; DPRINTK("EXIT\n"); - return 0; + return rc; } /** @@ -1979,6 +1979,10 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + /* collect port action mask recorded in dev actions */ + ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK; + /* process hotplug request */ if (dev->flags & ATA_DFLAG_DETACH) ata_eh_detach_dev(dev); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a4790be41d1..73902d33576 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -51,7 +51,7 @@ #define SECTOR_SIZE 512 -typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); +typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); @@ -273,8 +273,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) { int rc = 0; u8 scsi_cmd[MAX_COMMAND_SIZE]; - u8 args[7]; - struct scsi_sense_hdr sshdr; + u8 args[7], *sensebuf = NULL; + int cmd_result; if (arg == NULL) return -EINVAL; @@ -282,10 +282,14 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) if (copy_from_user(args, arg, sizeof(args))) return -EFAULT; + sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); + if (!sensebuf) + return -ENOMEM; + memset(scsi_cmd, 0, sizeof(scsi_cmd)); scsi_cmd[0] = ATA_16; scsi_cmd[1] = (3 << 1); /* Non-data */ - /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + scsi_cmd[2] = 0x20; /* cc but no off.line or data xfer */ scsi_cmd[4] = args[1]; scsi_cmd[6] = args[2]; scsi_cmd[8] = args[3]; @@ -295,11 +299,46 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) /* Good values for timeout and retries? Values below from scsi_ioctl_send_command() for default case... */ - if (scsi_execute_req(scsidev, scsi_cmd, DMA_NONE, NULL, 0, &sshdr, - (10*HZ), 5)) + cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0, + sensebuf, (10*HZ), 5, 0); + + if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */ + u8 *desc = sensebuf + 8; + cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ + + /* If we set cc then ATA pass-through will cause a + * check condition even if no error. Filter that. */ + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, + &sshdr); + if (sshdr.sense_key==0 && + sshdr.asc==0 && sshdr.ascq==0) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + + /* Send userspace ATA registers */ + if (sensebuf[0] == 0x72 && /* format is "descriptor" */ + desc[0] == 0x09) {/* code is "ATA Descriptor" */ + args[0] = desc[13]; /* status */ + args[1] = desc[3]; /* error */ + args[2] = desc[5]; /* sector count (0:7) */ + args[3] = desc[7]; /* lbal */ + args[4] = desc[9]; /* lbam */ + args[5] = desc[11]; /* lbah */ + args[6] = desc[12]; /* select */ + if (copy_to_user(arg, args, sizeof(args))) + rc = -EFAULT; + } + } + + if (cmd_result) { rc = -EIO; + goto error; + } - /* Need code to retrieve data from check condition? */ + error: + kfree(sensebuf); return rc; } @@ -372,7 +411,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, if (cmd->use_sg) { qc->__sg = (struct scatterlist *) cmd->request_buffer; qc->n_elem = cmd->use_sg; - } else { + } else if (cmd->request_bufflen) { qc->__sg = &qc->sgent; qc->n_elem = 1; } @@ -935,7 +974,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) /** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command * @qc: Storage for translated ATA taskfile - * @scsicmd: SCSI command to translate * * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY * (to start). Perhaps these commands should be preceded by @@ -948,22 +986,25 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) * RETURNS: * Zero on success, non-zero on error. */ - -static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, - const u8 *scsicmd) +static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) { + struct scsi_cmnd *scmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; + const u8 *cdb = scmd->cmnd; + + if (scmd->cmd_len < 5) + goto invalid_fld; tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf->protocol = ATA_PROT_NODATA; - if (scsicmd[1] & 0x1) { + if (cdb[1] & 0x1) { ; /* ignore IMMED bit, violates sat-r05 */ } - if (scsicmd[4] & 0x2) + if (cdb[4] & 0x2) goto invalid_fld; /* LOEJ bit set not supported */ - if (((scsicmd[4] >> 4) & 0xf) != 0) + if (((cdb[4] >> 4) & 0xf) != 0) goto invalid_fld; /* power conditions not supported */ - if (scsicmd[4] & 0x1) { + if (cdb[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ if (qc->dev->flags & ATA_DFLAG_LBA) { @@ -981,11 +1022,10 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, } tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ - } else { - tf->nsect = 0; /* time period value (0 implies now) */ - tf->command = ATA_CMD_STANDBY; - /* Consider: ATA STANDBY IMMEDIATE command */ - } + } else + /* Issue ATA STANDBY IMMEDIATE command */ + tf->command = ATA_CMD_STANDBYNOW1; + /* * Standby and Idle condition timers could be implemented but that * would require libata to implement the Power condition mode page @@ -996,7 +1036,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, return 0; invalid_fld: - ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ return 1; } @@ -1005,7 +1045,6 @@ invalid_fld: /** * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command * @qc: Storage for translated ATA taskfile - * @scsicmd: SCSI command to translate (ignored) * * Sets up an ATA taskfile to issue FLUSH CACHE or * FLUSH CACHE EXT. @@ -1016,8 +1055,7 @@ invalid_fld: * RETURNS: * Zero on success, non-zero on error. */ - -static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc) { struct ata_taskfile *tf = &qc->tf; @@ -1034,7 +1072,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs /** * scsi_6_lba_len - Get LBA and transfer length - * @scsicmd: SCSI command to translate + * @cdb: SCSI command to translate * * Calculate LBA and transfer length for 6-byte commands. * @@ -1042,18 +1080,17 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs * @plba: the LBA * @plen: the transfer length */ - -static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen) { u64 lba = 0; u32 len = 0; VPRINTK("six-byte command\n"); - lba |= ((u64)scsicmd[2]) << 8; - lba |= ((u64)scsicmd[3]); + lba |= ((u64)cdb[2]) << 8; + lba |= ((u64)cdb[3]); - len |= ((u32)scsicmd[4]); + len |= ((u32)cdb[4]); *plba = lba; *plen = len; @@ -1061,7 +1098,7 @@ static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) /** * scsi_10_lba_len - Get LBA and transfer length - * @scsicmd: SCSI command to translate + * @cdb: SCSI command to translate * * Calculate LBA and transfer length for 10-byte commands. * @@ -1069,21 +1106,20 @@ static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) * @plba: the LBA * @plen: the transfer length */ - -static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +static void scsi_10_lba_len(const u8 *cdb, u64 *plba, u32 *plen) { u64 lba = 0; u32 len = 0; VPRINTK("ten-byte command\n"); - lba |= ((u64)scsicmd[2]) << 24; - lba |= ((u64)scsicmd[3]) << 16; - lba |= ((u64)scsicmd[4]) << 8; - lba |= ((u64)scsicmd[5]); + lba |= ((u64)cdb[2]) << 24; + lba |= ((u64)cdb[3]) << 16; + lba |= ((u64)cdb[4]) << 8; + lba |= ((u64)cdb[5]); - len |= ((u32)scsicmd[7]) << 8; - len |= ((u32)scsicmd[8]); + len |= ((u32)cdb[7]) << 8; + len |= ((u32)cdb[8]); *plba = lba; *plen = len; @@ -1091,7 +1127,7 @@ static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) /** * scsi_16_lba_len - Get LBA and transfer length - * @scsicmd: SCSI command to translate + * @cdb: SCSI command to translate * * Calculate LBA and transfer length for 16-byte commands. * @@ -1099,27 +1135,26 @@ static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) * @plba: the LBA * @plen: the transfer length */ - -static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +static void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen) { u64 lba = 0; u32 len = 0; VPRINTK("sixteen-byte command\n"); - lba |= ((u64)scsicmd[2]) << 56; - lba |= ((u64)scsicmd[3]) << 48; - lba |= ((u64)scsicmd[4]) << 40; - lba |= ((u64)scsicmd[5]) << 32; - lba |= ((u64)scsicmd[6]) << 24; - lba |= ((u64)scsicmd[7]) << 16; - lba |= ((u64)scsicmd[8]) << 8; - lba |= ((u64)scsicmd[9]); + lba |= ((u64)cdb[2]) << 56; + lba |= ((u64)cdb[3]) << 48; + lba |= ((u64)cdb[4]) << 40; + lba |= ((u64)cdb[5]) << 32; + lba |= ((u64)cdb[6]) << 24; + lba |= ((u64)cdb[7]) << 16; + lba |= ((u64)cdb[8]) << 8; + lba |= ((u64)cdb[9]); - len |= ((u32)scsicmd[10]) << 24; - len |= ((u32)scsicmd[11]) << 16; - len |= ((u32)scsicmd[12]) << 8; - len |= ((u32)scsicmd[13]); + len |= ((u32)cdb[10]) << 24; + len |= ((u32)cdb[11]) << 16; + len |= ((u32)cdb[12]) << 8; + len |= ((u32)cdb[13]); *plba = lba; *plen = len; @@ -1128,7 +1163,6 @@ static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) /** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile - * @scsicmd: SCSI command to translate * * Converts SCSI VERIFY command to an ATA READ VERIFY command. * @@ -1138,23 +1172,28 @@ static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) * RETURNS: * Zero on success, non-zero on error. */ - -static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc) { + struct scsi_cmnd *scmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; u64 dev_sectors = qc->dev->n_sectors; + const u8 *cdb = scmd->cmnd; u64 block; u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if (scsicmd[0] == VERIFY) - scsi_10_lba_len(scsicmd, &block, &n_block); - else if (scsicmd[0] == VERIFY_16) - scsi_16_lba_len(scsicmd, &block, &n_block); - else + if (cdb[0] == VERIFY) { + if (scmd->cmd_len < 10) + goto invalid_fld; + scsi_10_lba_len(cdb, &block, &n_block); + } else if (cdb[0] == VERIFY_16) { + if (scmd->cmd_len < 16) + goto invalid_fld; + scsi_16_lba_len(cdb, &block, &n_block); + } else goto invalid_fld; if (!n_block) @@ -1229,24 +1268,23 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc return 0; invalid_fld: - ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ return 1; out_of_range: - ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); /* "Logical Block Address out of range" */ return 1; nothing_to_do: - qc->scsicmd->result = SAM_STAT_GOOD; + scmd->result = SAM_STAT_GOOD; return 1; } /** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile - * @scsicmd: SCSI command to translate * * Converts any of six SCSI read/write commands into the * ATA counterpart, including starting sector (LBA), @@ -1262,29 +1300,33 @@ nothing_to_do: * RETURNS: * Zero on success, non-zero on error. */ - -static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) +static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) { + struct scsi_cmnd *scmd = qc->scsicmd; + const u8 *cdb = scmd->cmnd; unsigned int tf_flags = 0; u64 block; u32 n_block; int rc; - if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || - scsicmd[0] == WRITE_16) + if (cdb[0] == WRITE_10 || cdb[0] == WRITE_6 || cdb[0] == WRITE_16) tf_flags |= ATA_TFLAG_WRITE; /* Calculate the SCSI LBA, transfer length and FUA. */ - switch (scsicmd[0]) { + switch (cdb[0]) { case READ_10: case WRITE_10: - scsi_10_lba_len(scsicmd, &block, &n_block); - if (unlikely(scsicmd[1] & (1 << 3))) + if (unlikely(scmd->cmd_len < 10)) + goto invalid_fld; + scsi_10_lba_len(cdb, &block, &n_block); + if (unlikely(cdb[1] & (1 << 3))) tf_flags |= ATA_TFLAG_FUA; break; case READ_6: case WRITE_6: - scsi_6_lba_len(scsicmd, &block, &n_block); + if (unlikely(scmd->cmd_len < 6)) + goto invalid_fld; + scsi_6_lba_len(cdb, &block, &n_block); /* for 6-byte r/w commands, transfer length 0 * means 256 blocks of data, not 0 block. @@ -1294,8 +1336,10 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm break; case READ_16: case WRITE_16: - scsi_16_lba_len(scsicmd, &block, &n_block); - if (unlikely(scsicmd[1] & (1 << 3))) + if (unlikely(scmd->cmd_len < 16)) + goto invalid_fld; + scsi_16_lba_len(cdb, &block, &n_block); + if (unlikely(cdb[1] & (1 << 3))) tf_flags |= ATA_TFLAG_FUA; break; default: @@ -1326,17 +1370,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm goto out_of_range; /* treat all other errors as -EINVAL, fall through */ invalid_fld: - ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ return 1; out_of_range: - ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); /* "Logical Block Address out of range" */ return 1; nothing_to_do: - qc->scsicmd->result = SAM_STAT_GOOD; + scmd->result = SAM_STAT_GOOD; return 1; } @@ -1456,7 +1500,6 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_xlat_func_t xlat_func) { struct ata_queued_cmd *qc; - u8 *scsicmd = cmd->cmnd; int is_io = xlat_func == ata_scsi_rw_xlat; VPRINTK("ENTER\n"); @@ -1488,7 +1531,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, qc->complete_fn = ata_scsi_qc_complete; - if (xlat_func(qc, scsicmd)) + if (xlat_func(qc)) goto early_finish; /* select device, send command to hardware */ @@ -2344,7 +2387,6 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized - * @scsicmd: SCSI CDB associated with this PACKET command * * LOCKING: * spin_lock_irqsave(host lock) @@ -2352,25 +2394,25 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * RETURNS: * Zero on success, non-zero on failure. */ - -static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) +static unsigned int atapi_xlat(struct ata_queued_cmd *qc) { - struct scsi_cmnd *cmd = qc->scsicmd; + struct scsi_cmnd *scmd = qc->scsicmd; struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); - int nodata = (cmd->sc_data_direction == DMA_NONE); + int nodata = (scmd->sc_data_direction == DMA_NONE); if (!using_pio) /* Check whether ATAPI DMA is safe */ if (ata_check_atapi_dma(qc)) using_pio = 1; - memcpy(&qc->cdb, scsicmd, dev->cdb_len); + memset(qc->cdb, 0, dev->cdb_len); + memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len); qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - if (cmd->sc_data_direction == DMA_TO_DEVICE) { + if (scmd->sc_data_direction == DMA_TO_DEVICE) { qc->tf.flags |= ATA_TFLAG_WRITE; DPRINTK("direction: write\n"); } @@ -2392,12 +2434,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; - if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE)) + if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE)) /* some SATA bridges need us to indicate data xfer direction */ qc->tf.feature |= ATAPI_DMADIR; } - qc->nbytes = cmd->request_bufflen; + qc->nbytes = scmd->request_bufflen; return 0; } @@ -2517,28 +2559,27 @@ ata_scsi_map_proto(u8 byte1) /** * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile * @qc: command structure to be initialized - * @scsicmd: SCSI command to convert * * Handles either 12 or 16-byte versions of the CDB. * * RETURNS: * Zero on success, non-zero on failure. */ -static unsigned int -ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) +static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) { struct ata_taskfile *tf = &(qc->tf); - struct scsi_cmnd *cmd = qc->scsicmd; + struct scsi_cmnd *scmd = qc->scsicmd; struct ata_device *dev = qc->dev; + const u8 *cdb = scmd->cmnd; - if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) + if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) goto invalid_fld; /* We may not issue DMA commands if no DMA mode is set */ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) goto invalid_fld; - if (scsicmd[1] & 0xe0) + if (cdb[1] & 0xe0) /* PIO multi not supported yet */ goto invalid_fld; @@ -2546,18 +2587,18 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) * 12 and 16 byte CDBs use different offsets to * provide the various register values. */ - if (scsicmd[0] == ATA_16) { + if (cdb[0] == ATA_16) { /* * 16-byte CDB - may contain extended commands. * * If that is the case, copy the upper byte register values. */ - if (scsicmd[1] & 0x01) { - tf->hob_feature = scsicmd[3]; - tf->hob_nsect = scsicmd[5]; - tf->hob_lbal = scsicmd[7]; - tf->hob_lbam = scsicmd[9]; - tf->hob_lbah = scsicmd[11]; + if (cdb[1] & 0x01) { + tf->hob_feature = cdb[3]; + tf->hob_nsect = cdb[5]; + tf->hob_lbal = cdb[7]; + tf->hob_lbam = cdb[9]; + tf->hob_lbah = cdb[11]; tf->flags |= ATA_TFLAG_LBA48; } else tf->flags &= ~ATA_TFLAG_LBA48; @@ -2565,26 +2606,26 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) /* * Always copy low byte, device and command registers. */ - tf->feature = scsicmd[4]; - tf->nsect = scsicmd[6]; - tf->lbal = scsicmd[8]; - tf->lbam = scsicmd[10]; - tf->lbah = scsicmd[12]; - tf->device = scsicmd[13]; - tf->command = scsicmd[14]; + tf->feature = cdb[4]; + tf->nsect = cdb[6]; + tf->lbal = cdb[8]; + tf->lbam = cdb[10]; + tf->lbah = cdb[12]; + tf->device = cdb[13]; + tf->command = cdb[14]; } else { /* * 12-byte CDB - incapable of extended commands. */ tf->flags &= ~ATA_TFLAG_LBA48; - tf->feature = scsicmd[3]; - tf->nsect = scsicmd[4]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[6]; - tf->lbah = scsicmd[7]; - tf->device = scsicmd[8]; - tf->command = scsicmd[9]; + tf->feature = cdb[3]; + tf->nsect = cdb[4]; + tf->lbal = cdb[5]; + tf->lbam = cdb[6]; + tf->lbah = cdb[7]; + tf->device = cdb[8]; + tf->command = cdb[9]; } /* * If slave is possible, enforce correct master/slave bit @@ -2611,7 +2652,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) */ tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); - if (cmd->sc_data_direction == DMA_TO_DEVICE) + if (scmd->sc_data_direction == DMA_TO_DEVICE) tf->flags |= ATA_TFLAG_WRITE; /* @@ -2620,7 +2661,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE; + qc->nsect = scmd->request_bufflen / ATA_SECT_SIZE; /* request result TF */ qc->flags |= ATA_QCFLAG_RESULT_TF; @@ -2628,7 +2669,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) return 0; invalid_fld: - ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00); + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00); /* "Invalid field in cdb" */ return 1; } @@ -2701,22 +2742,29 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, #endif } -static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd, +static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *), struct ata_device *dev) { int rc = 0; + if (unlikely(!scmd->cmd_len)) { + ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n"); + scmd->result = DID_ERROR << 16; + done(scmd); + return 0; + } + if (dev->class == ATA_DEV_ATA) { ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, - cmd->cmnd[0]); + scmd->cmnd[0]); if (xlat_func) - rc = ata_scsi_translate(dev, cmd, done, xlat_func); + rc = ata_scsi_translate(dev, scmd, done, xlat_func); else - ata_scsi_simulate(dev, cmd, done); + ata_scsi_simulate(dev, scmd, done); } else - rc = ata_scsi_translate(dev, cmd, done, atapi_xlat); + rc = ata_scsi_translate(dev, scmd, done, atapi_xlat); return rc; } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 10ee22ae5c1..12c88c58803 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -827,7 +827,8 @@ void ata_bmdma_error_handler(struct ata_port *ap) */ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) { - ata_bmdma_stop(qc); + if (qc->ap->ioaddr.bmdma_addr) + ata_bmdma_stop(qc); } #ifdef CONFIG_PCI @@ -870,7 +871,8 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; bmdma = pci_resource_start(pdev, 4); if (bmdma) { - if (inb(bmdma + 2) & 0x80) + if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (inb(bmdma + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; probe_ent->port[p].bmdma_addr = bmdma; } @@ -886,7 +888,8 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int bmdma = pci_resource_start(pdev, 4); if (bmdma) { bmdma += 8; - if(inb(bmdma + 2) & 0x80) + if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (inb(bmdma + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; probe_ent->port[p].bmdma_addr = bmdma; } @@ -914,13 +917,14 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, probe_ent->irq_flags = IRQF_SHARED; if (port_mask & ATA_PORT_PRIMARY) { - probe_ent->irq = ATA_PRIMARY_IRQ; + probe_ent->irq = ATA_PRIMARY_IRQ(pdev); probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD; probe_ent->port[0].altstatus_addr = probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL; if (bmdma) { probe_ent->port[0].bmdma_addr = bmdma; - if (inb(bmdma + 2) & 0x80) + if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (inb(bmdma + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[0]); @@ -929,15 +933,16 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, if (port_mask & ATA_PORT_SECONDARY) { if (probe_ent->irq) - probe_ent->irq2 = ATA_SECONDARY_IRQ; + probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev); else - probe_ent->irq = ATA_SECONDARY_IRQ; + probe_ent->irq = ATA_SECONDARY_IRQ(pdev); probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD; probe_ent->port[1].altstatus_addr = probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL; if (bmdma) { probe_ent->port[1].bmdma_addr = bmdma + 8; - if (inb(bmdma + 10) & 0x80) + if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (inb(bmdma + 10) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[1]); @@ -1027,13 +1032,15 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, #endif } - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - disable_dev_on_err = 0; - goto err_out; - } - - if (legacy_mode) { + if (!legacy_mode) { + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { + disable_dev_on_err = 0; + goto err_out; + } + } else { + /* Deal with combined mode hack. This side of the logic all + goes away once the combined mode hack is killed in 2.6.21 */ if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) { struct resource *conflict, res; res.start = ATA_PRIMARY_CMD; @@ -1071,6 +1078,13 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, } } else legacy_mode |= ATA_PORT_SECONDARY; + + if (legacy_mode & ATA_PORT_PRIMARY) + pci_request_region(pdev, 1, DRV_NAME); + if (legacy_mode & ATA_PORT_SECONDARY) + pci_request_region(pdev, 3, DRV_NAME); + /* If there is a DMA resource, allocate it */ + pci_request_region(pdev, 4, DRV_NAME); } /* we have legacy mode, but all ports are unavailable */ @@ -1114,11 +1128,20 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, err_out_ent: kfree(probe_ent); err_out_regions: - if (legacy_mode & ATA_PORT_PRIMARY) - release_region(ATA_PRIMARY_CMD, 8); - if (legacy_mode & ATA_PORT_SECONDARY) - release_region(ATA_SECONDARY_CMD, 8); - pci_release_regions(pdev); + /* All this conditional stuff is needed for the combined mode hack + until 2.6.21 when it can go */ + if (legacy_mode) { + pci_release_region(pdev, 4); + if (legacy_mode & ATA_PORT_PRIMARY) { + release_region(ATA_PRIMARY_CMD, 8); + pci_release_region(pdev, 1); + } + if (legacy_mode & ATA_PORT_SECONDARY) { + release_region(ATA_SECONDARY_CMD, 8); + pci_release_region(pdev, 3); + } + } else + pci_release_regions(pdev); err_out: if (disable_dev_on_err) pci_disable_device(pdev); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 6f6672c5513..504e1dbfffd 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -36,15 +36,22 @@ enum { static int atiixp_pre_reset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - static struct pci_bits atiixp_enable_bits[] = { + static const struct pci_bits atiixp_enable_bits[] = { { 0x48, 1, 0x01, 0x00 }, { 0x48, 1, 0x08, 0x00 } }; + u8 udma; if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; - ap->cbl = ATA_CBL_PATA80; + /* Hack from drivers/ide/pci. Really we want to know how to do the + raw detection not play follow the bios mode guess */ + pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma); + if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 15841a56369..449162cbf93 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -197,7 +197,7 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) { static const u8 udma_data[] = { - 0x31, 0x21, 0x11, 0x25, 0x15, 0x05 + 0x30, 0x20, 0x10, 0x20, 0x10, 0x00 }; static const u8 mwdma_data[] = { 0x30, 0x20, 0x10 @@ -213,12 +213,21 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) pci_read_config_byte(pdev, pciD, ®D); pci_read_config_byte(pdev, pciU, ®U); - regD &= ~(0x20 << shift); - regU &= ~(0x35 << shift); + /* DMA bits off */ + regD &= ~(0x20 << adev->devno); + /* DMA control bits */ + regU &= ~(0x30 << shift); + /* DMA timing bits */ + regU &= ~(0x05 << adev->devno); - if (adev->dma_mode >= XFER_UDMA_0) + if (adev->dma_mode >= XFER_UDMA_0) { + /* Merge thge timing value */ regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift; - else + /* Merge the control bits */ + regU |= 1 << adev->devno; /* UDMA on */ + if (adev->dma_mode > 2) /* 15nS timing */ + regU |= 4 << adev->devno; + } else regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift; regD |= 0x20 << adev->devno; @@ -239,8 +248,8 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 dma_intr; - int dma_reg = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; - int dma_mask = ap->port_no ? ARTTIM2 : CFR; + int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; + int dma_reg = ap->port_no ? ARTTIM2 : CFR; ata_bmdma_stop(qc); diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 1c628014dae..b1ca207e354 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -372,7 +372,8 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static int cs5530_reinit_one(struct pci_dev *pdev) { /* If we fail on resume we are doomed */ - BUG_ON(cs5530_init_chip()); + if (cs5530_init_chip()) + BUG(); return ata_pci_device_resume(pdev); } diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 47082df7199..dfb306057cf 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.5.1" +#define DRV_VERSION "0.5.2" struct hpt_clock { u8 xfer_speed; @@ -416,7 +416,7 @@ static const char *bad_ata100_5[] = { static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { - if (adev->class != ATA_DEV_ATA) { + if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) mask &= ~ATA_MASK_UDMA; if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) @@ -749,7 +749,7 @@ static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int mscreg = 0x50 + 2 * ap->port_no; + int mscreg = 0x50 + 4 * ap->port_no; u8 bwsr_stat, msc_stat; pci_read_config_byte(pdev, 0x6A, &bwsr_stat); diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index f6817b4093a..886fab9aa62 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3" +#define DRV_VERSION "0.3.2" enum { HPT_PCI_FAST = (1 << 31), @@ -297,11 +297,11 @@ static int hpt3x2n_pair_idle(struct ata_port *ap) return 0; } -static int hpt3x2n_use_dpll(struct ata_port *ap, int reading) +static int hpt3x2n_use_dpll(struct ata_port *ap, int writing) { long flags = (long)ap->host->private_data; /* See if we should use the DPLL */ - if (reading == 0) + if (writing) return USE_DPLL; /* Needed for write */ if (flags & PCI66) return USE_DPLL; /* Needed at 66Mhz */ diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 0b56ff3d1cf..e8afd486434 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -476,6 +476,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) /** * it821x_smart_set_mode - mode setting * @ap: interface to set up + * @unused: device that failed (error only) * * Use a non standard set_mode function. We don't want to be tuned. * The BIOS configured everything. Our job is not to fiddle. We @@ -483,7 +484,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) * and respect them. */ -static void it821x_smart_set_mode(struct ata_port *ap) +static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused) { int dma_enabled = 0; int i; @@ -512,6 +513,7 @@ static void it821x_smart_set_mode(struct ata_port *ap) } } } + return 0; } /** diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index cb8924109f5..23b8aab3ebd 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -23,9 +23,9 @@ #include <scsi/scsi_host.h> #define DRV_NAME "pata_ixp4xx_cf" -#define DRV_VERSION "0.1.1" +#define DRV_VERSION "0.1.1ac1" -static void ixp4xx_set_mode(struct ata_port *ap) +static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device *adev) { int i; @@ -38,6 +38,7 @@ static void ixp4xx_set_mode(struct ata_port *ap) dev->flags |= ATA_DFLAG_PIO; } } + return 0; } static void ixp4xx_phy_reset(struct ata_port *ap) diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 2d661cb4df3..d50264af284 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -204,20 +204,12 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i u32 reg; - if (id->driver_data != 368) { - /* Put the controller into AHCI mode in case the AHCI driver - has not yet been loaded. This can be done with either - function present */ + /* PATA controller is fn 1, AHCI is fn 0 */ + if (id->driver_data != 368 && PCI_FUNC(pdev->devfn) != 1) + return -ENODEV; - /* FIXME: We may want a way to override this in future */ - pci_write_config_byte(pdev, 0x41, 0xa1); - - /* PATA controller is fn 1, AHCI is fn 0 */ - if (PCI_FUNC(pdev->devfn) != 1) - return -ENODEV; - } - if ( id->driver_data == 365 || id->driver_data == 366) { - /* The 365/66 have two PATA channels, redirect the second */ + /* The 365/66 have two PATA channels, redirect the second */ + if (id->driver_data == 365 || id->driver_data == 366) { pci_read_config_dword(pdev, 0x80, ®); reg |= (1 << 24); /* IDE1 to PATA IDE secondary */ pci_write_config_dword(pdev, 0x80, reg); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index e7bf9d89c8e..581cb33c6f4 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -96,6 +96,7 @@ static int pio_mask = 0x1F; /* PIO range for autospeed devices */ /** * legacy_set_mode - mode setting * @ap: IDE interface + * @unused: Device that failed when error is returned * * Use a non standard set_mode function. We don't want to be tuned. * @@ -105,7 +106,7 @@ static int pio_mask = 0x1F; /* PIO range for autospeed devices */ * expand on this as per hdparm in the base kernel. */ -static void legacy_set_mode(struct ata_port *ap) +static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) { int i; @@ -118,6 +119,7 @@ static void legacy_set_mode(struct ata_port *ap) dev->flags |= ATA_DFLAG_PIO; } } + return 0; } static struct scsi_host_template legacy_sht = { diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 443b1d85c6c..40ae11cbfda 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -30,7 +30,7 @@ static int pio_mask = 1; * Provide our own set_mode() as we don't want to change anything that has * already been configured.. */ -static void pata_platform_set_mode(struct ata_port *ap) +static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused) { int i; @@ -44,6 +44,7 @@ static void pata_platform_set_mode(struct ata_port *ap) dev->flags |= ATA_DFLAG_PIO; } } + return 0; } static void pata_platform_host_stop(struct ata_host *host) diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index adf4cc134f2..cec0729225e 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -52,19 +52,20 @@ static void rz1000_error_handler(struct ata_port *ap) /** * rz1000_set_mode - mode setting function * @ap: ATA interface + * @unused: returned device on set_mode failure * * Use a non standard set_mode function. We don't want to be tuned. We * would prefer to be BIOS generic but for the fact our hardware is * whacked out. */ -static void rz1000_set_mode(struct ata_port *ap) +static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) { int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; - if (ata_dev_enabled(dev)) { + if (ata_dev_ready(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; @@ -72,6 +73,7 @@ static void rz1000_set_mode(struct ata_port *ap) dev->flags |= ATA_DFLAG_PIO; } } + return 0; } diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 32cf0bfa892..e8dfd8fc3ff 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -135,7 +135,7 @@ static void sil680_error_handler(struct ata_port *ap) static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev) { static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 }; - static u16 speed_t[5] = { 0x328A, 0x1281, 0x1281, 0x10C3, 0x10C1 }; + static u16 speed_t[5] = { 0x328A, 0x2283, 0x1281, 0x10C3, 0x10C1 }; unsigned long tfaddr = sil680_selreg(ap, 0x02); unsigned long addr = sil680_seldev(ap, adev, 0x04); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index ff93e8f71cf..f0b6c3b7142 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -23,6 +23,7 @@ * VIA VT8233c - UDMA100 * VIA VT8235 - UDMA133 * VIA VT8237 - UDMA133 + * VIA VT8237S - UDMA133 * VIA VT8251 - UDMA133 * * Most registers remain compatible across chips. Others start reserved @@ -61,7 +62,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_via" -#define DRV_VERSION "0.2.0" +#define DRV_VERSION "0.2.1" /* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx @@ -95,6 +96,7 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { + { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES}, @@ -395,7 +397,7 @@ static void via_config_fifo(struct pci_dev *pdev, unsigned int flags) enable &= 3; if (flags & VIA_SET_FIFO) { - u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; + static const u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; u8 fifo; pci_read_config_byte(pdev, 0x43, &fifo); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 1b8e0eb9e03..aae0b5201c1 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -523,8 +523,7 @@ static const struct ata_port_info mv_port_info[] = { }, { /* chip_7042 */ .sht = &mv_sht, - .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | - MV_FLAG_DUAL_HC), + .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_iie_ops, @@ -545,6 +544,8 @@ static const struct pci_device_id mv_pci_tbl[] = { { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, + { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, + { } /* terminate list */ }; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 0d316eb3c21..f7a963eb1f0 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -270,14 +270,6 @@ static const struct pci_device_id nv_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, - { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x0550), GENERIC }, /* MCP67 */ - { PCI_VDEVICE(NVIDIA, 0x0551), GENERIC }, /* MCP67 */ - { PCI_VDEVICE(NVIDIA, 0x0552), GENERIC }, /* MCP67 */ - { PCI_VDEVICE(NVIDIA, 0x0553), GENERIC }, /* MCP67 */ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, @@ -708,7 +700,6 @@ static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) static int nv_host_intr(struct ata_port *ap, u8 irq_stat) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); - int handled; /* freeze if hotplugged */ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { @@ -727,13 +718,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat) } /* handle interrupt */ - handled = ata_host_intr(ap, qc); - if (unlikely(!handled)) { - /* spurious, clear it */ - ata_check_status(ap); - } - - return 1; + return ata_host_intr(ap, qc); } static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) @@ -760,6 +745,11 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) >> (NV_INT_PORT_SHIFT * i); + if(ata_tag_valid(ap->active_tag)) + /** NV_INT_DEV indication seems unreliable at times + at least in ADMA mode. Force it on always when a + command is active, to prevent losing interrupts. */ + irq_stat |= NV_INT_DEV; handled += nv_host_intr(ap, irq_stat); continue; } diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index d89c9590b84..46d8a94669b 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -135,26 +135,31 @@ static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, ioaddr->ctl_addr); + writeb(tf->ctl, (void __iomem *) ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); - writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); - writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); - writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); - writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); + writew(tf->feature | (((u16)tf->hob_feature) << 8), + (void __iomem *) ioaddr->feature_addr); + writew(tf->nsect | (((u16)tf->hob_nsect) << 8), + (void __iomem *) ioaddr->nsect_addr); + writew(tf->lbal | (((u16)tf->hob_lbal) << 8), + (void __iomem *) ioaddr->lbal_addr); + writew(tf->lbam | (((u16)tf->hob_lbam) << 8), + (void __iomem *) ioaddr->lbam_addr); + writew(tf->lbah | (((u16)tf->hob_lbah) << 8), + (void __iomem *) ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, ioaddr->feature_addr); - writew(tf->nsect, ioaddr->nsect_addr); - writew(tf->lbal, ioaddr->lbal_addr); - writew(tf->lbam, ioaddr->lbam_addr); - writew(tf->lbah, ioaddr->lbah_addr); + writew(tf->feature, (void __iomem *) ioaddr->feature_addr); + writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr); + writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr); + writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr); + writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr); } if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, ioaddr->device_addr); + writeb(tf->device, (void __iomem *) ioaddr->device_addr); ata_wait_idle(ap); } @@ -166,12 +171,12 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) u16 nsect, lbal, lbam, lbah, feature; tf->command = k2_stat_check_status(ap); - tf->device = readw(ioaddr->device_addr); - feature = readw(ioaddr->error_addr); - nsect = readw(ioaddr->nsect_addr); - lbal = readw(ioaddr->lbal_addr); - lbam = readw(ioaddr->lbam_addr); - lbah = readw(ioaddr->lbah_addr); + tf->device = readw((void __iomem *)ioaddr->device_addr); + feature = readw((void __iomem *)ioaddr->error_addr); + nsect = readw((void __iomem *)ioaddr->nsect_addr); + lbal = readw((void __iomem *)ioaddr->lbal_addr); + lbam = readw((void __iomem *)ioaddr->lbam_addr); + lbah = readw((void __iomem *)ioaddr->lbah_addr); tf->feature = feature; tf->nsect = nsect; diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 5c603ca3a50..a43aec62d50 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -128,7 +128,8 @@ static const struct ata_port_operations uli_ops = { static struct ata_port_info uli_port_info = { .sht = &uli_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_IGN_SIMPLEX, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &uli_ops, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 1c7f19aecc2..d3d5c0d5703 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -74,9 +74,11 @@ enum { static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void svia_noop_freeze(struct ata_port *ap); static void vt6420_error_handler(struct ata_port *ap); static const struct pci_device_id svia_pci_tbl[] = { + { PCI_VDEVICE(VIA, 0x5337), vt6420 }, { PCI_VDEVICE(VIA, 0x0591), vt6420 }, { PCI_VDEVICE(VIA, 0x3149), vt6420 }, { PCI_VDEVICE(VIA, 0x3249), vt6421 }, @@ -127,7 +129,7 @@ static const struct ata_port_operations vt6420_sata_ops = { .qc_issue = ata_qc_issue_prot, .data_xfer = ata_pio_data_xfer, - .freeze = ata_bmdma_freeze, + .freeze = svia_noop_freeze, .thaw = ata_bmdma_thaw, .error_handler = vt6420_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, @@ -203,6 +205,15 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) outl(val, ap->ioaddr.scr_addr + (4 * sc_reg)); } +static void svia_noop_freeze(struct ata_port *ap) +{ + /* Some VIA controllers choke if ATA_NIEN is manipulated in + * certain way. Leave it alone and just clear pending IRQ. + */ + ata_chk_status(ap); + ata_bmdma_irq_clear(ap); +} + /** * vt6420_prereset - prereset for vt6420 * @ap: target ATA port diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index e654b990b90..0fa1b89f76d 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -149,21 +149,26 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); - writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); - writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); - writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); - writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); + writew(tf->feature | (((u16)tf->hob_feature) << 8), + (void __iomem *) ioaddr->feature_addr); + writew(tf->nsect | (((u16)tf->hob_nsect) << 8), + (void __iomem *) ioaddr->nsect_addr); + writew(tf->lbal | (((u16)tf->hob_lbal) << 8), + (void __iomem *) ioaddr->lbal_addr); + writew(tf->lbam | (((u16)tf->hob_lbam) << 8), + (void __iomem *) ioaddr->lbam_addr); + writew(tf->lbah | (((u16)tf->hob_lbah) << 8), + (void __iomem *) ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, ioaddr->feature_addr); - writew(tf->nsect, ioaddr->nsect_addr); - writew(tf->lbal, ioaddr->lbal_addr); - writew(tf->lbam, ioaddr->lbam_addr); - writew(tf->lbah, ioaddr->lbah_addr); + writew(tf->feature, (void __iomem *) ioaddr->feature_addr); + writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr); + writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr); + writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr); + writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr); } if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, ioaddr->device_addr); + writeb(tf->device, (void __iomem *) ioaddr->device_addr); ata_wait_idle(ap); } @@ -175,12 +180,12 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) u16 nsect, lbal, lbam, lbah, feature; tf->command = ata_check_status(ap); - tf->device = readw(ioaddr->device_addr); - feature = readw(ioaddr->error_addr); - nsect = readw(ioaddr->nsect_addr); - lbal = readw(ioaddr->lbal_addr); - lbam = readw(ioaddr->lbam_addr); - lbah = readw(ioaddr->lbah_addr); + tf->device = readw((void __iomem *) ioaddr->device_addr); + feature = readw((void __iomem *) ioaddr->error_addr); + nsect = readw((void __iomem *) ioaddr->nsect_addr); + lbal = readw((void __iomem *) ioaddr->lbal_addr); + lbam = readw((void __iomem *) ioaddr->lbam_addr); + lbah = readw((void __iomem *) ioaddr->lbah_addr); tf->feature = feature; tf->nsect = nsect; @@ -327,8 +332,8 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned lon port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET; port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET; port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET; - writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET); - writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET); + writel(0, (void __iomem *) base + VSC_SATA_UP_DESCRIPTOR_OFFSET); + writel(0, (void __iomem *) base + VSC_SATA_UP_DATA_BUFFER_OFFSET); } diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index 2ddd76fdbc4..33687454eb3 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -167,10 +167,6 @@ config ATM_ZATM_DEBUG Note that extended debugging may create certain race conditions itself. Enable this ONLY if you suspect problems with the driver. -# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y -# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then -# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n -# fi config ATM_NICSTAR tristate "IDT 77201 (NICStAR) (ForeRunnerLE)" depends on PCI && ATM && !64BIT diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 3a7b21ff30a..4aeb3d062ff 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -172,25 +172,6 @@ fore200e_irq_itoa(int irq) } -static void* -fore200e_kmalloc(int size, gfp_t flags) -{ - void *chunk = kzalloc(size, flags); - - if (!chunk) - printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags); - - return chunk; -} - - -static void -fore200e_kfree(void* chunk) -{ - kfree(chunk); -} - - /* allocate and align a chunk of memory intended to hold the data behing exchanged between the driver and the adapter (using streaming DVMA) */ @@ -206,7 +187,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i chunk->align_size = size; chunk->direction = direction; - chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); + chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); if (chunk->alloc_addr == NULL) return -ENOMEM; @@ -228,7 +209,7 @@ fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) { fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction); - fore200e_kfree(chunk->alloc_addr); + kfree(chunk->alloc_addr); } @@ -882,7 +863,7 @@ fore200e_sba_detect(const struct fore200e_bus* bus, int index) return NULL; } - fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (fore200e == NULL) return NULL; @@ -1505,7 +1486,7 @@ fore200e_open(struct atm_vcc *vcc) spin_unlock_irqrestore(&fore200e->q_lock, flags); - fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC); + fore200e_vcc = kzalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC); if (fore200e_vcc == NULL) { vc_map->vcc = NULL; return -ENOMEM; @@ -1526,7 +1507,7 @@ fore200e_open(struct atm_vcc *vcc) if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { up(&fore200e->rate_sf); - fore200e_kfree(fore200e_vcc); + kfree(fore200e_vcc); vc_map->vcc = NULL; return -EAGAIN; } @@ -1554,7 +1535,7 @@ fore200e_open(struct atm_vcc *vcc) fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - fore200e_kfree(fore200e_vcc); + kfree(fore200e_vcc); return -EINVAL; } @@ -1630,7 +1611,7 @@ fore200e_close(struct atm_vcc* vcc) clear_bit(ATM_VF_PARTIAL,&vcc->flags); ASSERT(fore200e_vcc); - fore200e_kfree(fore200e_vcc); + kfree(fore200e_vcc); } @@ -1831,7 +1812,7 @@ fore200e_getstats(struct fore200e* fore200e) u32 stats_dma_addr; if (fore200e->stats == NULL) { - fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); + fore200e->stats = kzalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); if (fore200e->stats == NULL) return -ENOMEM; } @@ -2002,17 +1983,6 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode) } -static inline unsigned int -fore200e_swap(unsigned int in) -{ -#if defined(__LITTLE_ENDIAN) - return swab32(in); -#else - return in; -#endif -} - - static int fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg) { @@ -2021,19 +1991,19 @@ fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg) if (fore200e_getstats(fore200e) < 0) return -EIO; - tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors); - tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors); - tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors); - tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors); - tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors); - tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors); - tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors); - tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) + - fore200e_swap(fore200e->stats->aal34.cells_transmitted) + - fore200e_swap(fore200e->stats->aal5.cells_transmitted); - tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) + - fore200e_swap(fore200e->stats->aal34.cells_received) + - fore200e_swap(fore200e->stats->aal5.cells_received); + tmp.section_bip = cpu_to_be32(fore200e->stats->oc3.section_bip8_errors); + tmp.line_bip = cpu_to_be32(fore200e->stats->oc3.line_bip24_errors); + tmp.path_bip = cpu_to_be32(fore200e->stats->oc3.path_bip8_errors); + tmp.line_febe = cpu_to_be32(fore200e->stats->oc3.line_febe_errors); + tmp.path_febe = cpu_to_be32(fore200e->stats->oc3.path_febe_errors); + tmp.corr_hcs = cpu_to_be32(fore200e->stats->oc3.corr_hcs_errors); + tmp.uncorr_hcs = cpu_to_be32(fore200e->stats->oc3.ucorr_hcs_errors); + tmp.tx_cells = cpu_to_be32(fore200e->stats->aal0.cells_transmitted) + + cpu_to_be32(fore200e->stats->aal34.cells_transmitted) + + cpu_to_be32(fore200e->stats->aal5.cells_transmitted); + tmp.rx_cells = cpu_to_be32(fore200e->stats->aal0.cells_received) + + cpu_to_be32(fore200e->stats->aal34.cells_received) + + cpu_to_be32(fore200e->stats->aal5.cells_received); if (arg) return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; @@ -2146,7 +2116,7 @@ fore200e_irq_request(struct fore200e* fore200e) static int __devinit fore200e_get_esi(struct fore200e* fore200e) { - struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); + struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); int ok, i; if (!prom) @@ -2154,7 +2124,7 @@ fore200e_get_esi(struct fore200e* fore200e) ok = fore200e->bus->prom_read(fore200e, prom); if (ok < 0) { - fore200e_kfree(prom); + kfree(prom); return -EBUSY; } @@ -2169,7 +2139,7 @@ fore200e_get_esi(struct fore200e* fore200e) fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; } - fore200e_kfree(prom); + kfree(prom); return 0; } @@ -2194,7 +2164,7 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e) DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); /* allocate the array of receive buffers */ - buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL); + buffer = bsq->buffer = kzalloc(nbr * sizeof(struct buffer), GFP_KERNEL); if (buffer == NULL) return -ENOMEM; @@ -2217,7 +2187,7 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e) while (i > 0) fore200e_chunk_free(fore200e, &buffer[ --i ].data); - fore200e_kfree(buffer); + kfree(buffer); return -ENOMEM; } @@ -2736,7 +2706,7 @@ fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent goto out; } - fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (fore200e == NULL) { err = -ENOMEM; goto out_disable; @@ -2999,8 +2969,8 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " 4b5b:\n" " crc_header_errors:\t\t%10u\n" " framing_errors:\t\t%10u\n", - fore200e_swap(fore200e->stats->phy.crc_header_errors), - fore200e_swap(fore200e->stats->phy.framing_errors)); + cpu_to_be32(fore200e->stats->phy.crc_header_errors), + cpu_to_be32(fore200e->stats->phy.framing_errors)); if (!left--) return sprintf(page, "\n" @@ -3012,13 +2982,13 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " path_febe_errors:\t\t%10u\n" " corr_hcs_errors:\t\t%10u\n" " ucorr_hcs_errors:\t\t%10u\n", - fore200e_swap(fore200e->stats->oc3.section_bip8_errors), - fore200e_swap(fore200e->stats->oc3.path_bip8_errors), - fore200e_swap(fore200e->stats->oc3.line_bip24_errors), - fore200e_swap(fore200e->stats->oc3.line_febe_errors), - fore200e_swap(fore200e->stats->oc3.path_febe_errors), - fore200e_swap(fore200e->stats->oc3.corr_hcs_errors), - fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors)); + cpu_to_be32(fore200e->stats->oc3.section_bip8_errors), + cpu_to_be32(fore200e->stats->oc3.path_bip8_errors), + cpu_to_be32(fore200e->stats->oc3.line_bip24_errors), + cpu_to_be32(fore200e->stats->oc3.line_febe_errors), + cpu_to_be32(fore200e->stats->oc3.path_febe_errors), + cpu_to_be32(fore200e->stats->oc3.corr_hcs_errors), + cpu_to_be32(fore200e->stats->oc3.ucorr_hcs_errors)); if (!left--) return sprintf(page,"\n" @@ -3029,12 +2999,12 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " vpi no conn:\t\t%10u\n" " vci out of range:\t\t%10u\n" " vci no conn:\t\t%10u\n", - fore200e_swap(fore200e->stats->atm.cells_transmitted), - fore200e_swap(fore200e->stats->atm.cells_received), - fore200e_swap(fore200e->stats->atm.vpi_bad_range), - fore200e_swap(fore200e->stats->atm.vpi_no_conn), - fore200e_swap(fore200e->stats->atm.vci_bad_range), - fore200e_swap(fore200e->stats->atm.vci_no_conn)); + cpu_to_be32(fore200e->stats->atm.cells_transmitted), + cpu_to_be32(fore200e->stats->atm.cells_received), + cpu_to_be32(fore200e->stats->atm.vpi_bad_range), + cpu_to_be32(fore200e->stats->atm.vpi_no_conn), + cpu_to_be32(fore200e->stats->atm.vci_bad_range), + cpu_to_be32(fore200e->stats->atm.vci_no_conn)); if (!left--) return sprintf(page,"\n" @@ -3042,9 +3012,9 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " TX:\t\t\t%10u\n" " RX:\t\t\t%10u\n" " dropped:\t\t\t%10u\n", - fore200e_swap(fore200e->stats->aal0.cells_transmitted), - fore200e_swap(fore200e->stats->aal0.cells_received), - fore200e_swap(fore200e->stats->aal0.cells_dropped)); + cpu_to_be32(fore200e->stats->aal0.cells_transmitted), + cpu_to_be32(fore200e->stats->aal0.cells_received), + cpu_to_be32(fore200e->stats->aal0.cells_dropped)); if (!left--) return sprintf(page,"\n" @@ -3060,15 +3030,15 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " RX:\t\t\t%10u\n" " dropped:\t\t\t%10u\n" " protocol errors:\t\t%10u\n", - fore200e_swap(fore200e->stats->aal34.cells_transmitted), - fore200e_swap(fore200e->stats->aal34.cells_received), - fore200e_swap(fore200e->stats->aal34.cells_dropped), - fore200e_swap(fore200e->stats->aal34.cells_crc_errors), - fore200e_swap(fore200e->stats->aal34.cells_protocol_errors), - fore200e_swap(fore200e->stats->aal34.cspdus_transmitted), - fore200e_swap(fore200e->stats->aal34.cspdus_received), - fore200e_swap(fore200e->stats->aal34.cspdus_dropped), - fore200e_swap(fore200e->stats->aal34.cspdus_protocol_errors)); + cpu_to_be32(fore200e->stats->aal34.cells_transmitted), + cpu_to_be32(fore200e->stats->aal34.cells_received), + cpu_to_be32(fore200e->stats->aal34.cells_dropped), + cpu_to_be32(fore200e->stats->aal34.cells_crc_errors), + cpu_to_be32(fore200e->stats->aal34.cells_protocol_errors), + cpu_to_be32(fore200e->stats->aal34.cspdus_transmitted), + cpu_to_be32(fore200e->stats->aal34.cspdus_received), + cpu_to_be32(fore200e->stats->aal34.cspdus_dropped), + cpu_to_be32(fore200e->stats->aal34.cspdus_protocol_errors)); if (!left--) return sprintf(page,"\n" @@ -3084,15 +3054,15 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " dropped:\t\t\t%10u\n" " CRC errors:\t\t%10u\n" " protocol errors:\t\t%10u\n", - fore200e_swap(fore200e->stats->aal5.cells_transmitted), - fore200e_swap(fore200e->stats->aal5.cells_received), - fore200e_swap(fore200e->stats->aal5.cells_dropped), - fore200e_swap(fore200e->stats->aal5.congestion_experienced), - fore200e_swap(fore200e->stats->aal5.cspdus_transmitted), - fore200e_swap(fore200e->stats->aal5.cspdus_received), - fore200e_swap(fore200e->stats->aal5.cspdus_dropped), - fore200e_swap(fore200e->stats->aal5.cspdus_crc_errors), - fore200e_swap(fore200e->stats->aal5.cspdus_protocol_errors)); + cpu_to_be32(fore200e->stats->aal5.cells_transmitted), + cpu_to_be32(fore200e->stats->aal5.cells_received), + cpu_to_be32(fore200e->stats->aal5.cells_dropped), + cpu_to_be32(fore200e->stats->aal5.congestion_experienced), + cpu_to_be32(fore200e->stats->aal5.cspdus_transmitted), + cpu_to_be32(fore200e->stats->aal5.cspdus_received), + cpu_to_be32(fore200e->stats->aal5.cspdus_dropped), + cpu_to_be32(fore200e->stats->aal5.cspdus_crc_errors), + cpu_to_be32(fore200e->stats->aal5.cspdus_protocol_errors)); if (!left--) return sprintf(page,"\n" @@ -3103,11 +3073,11 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " large b2:\t\t\t%10u\n" " RX PDUs:\t\t\t%10u\n" " TX PDUs:\t\t\t%10lu\n", - fore200e_swap(fore200e->stats->aux.small_b1_failed), - fore200e_swap(fore200e->stats->aux.large_b1_failed), - fore200e_swap(fore200e->stats->aux.small_b2_failed), - fore200e_swap(fore200e->stats->aux.large_b2_failed), - fore200e_swap(fore200e->stats->aux.rpd_alloc_failed), + cpu_to_be32(fore200e->stats->aux.small_b1_failed), + cpu_to_be32(fore200e->stats->aux.large_b1_failed), + cpu_to_be32(fore200e->stats->aux.small_b2_failed), + cpu_to_be32(fore200e->stats->aux.large_b2_failed), + cpu_to_be32(fore200e->stats->aux.rpd_alloc_failed), fore200e->tx_sat); if (!left--) diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 4dc10105d61..f96446c358b 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -1845,7 +1845,7 @@ static u16 __devinit read_bia (const hrz_dev * dev, u16 addr) /********** initialise a card **********/ -static int __init hrz_init (hrz_dev * dev) { +static int __devinit hrz_init (hrz_dev * dev) { int onefivefive; u16 chan; diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4bad2870c48..64558f45e6b 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -127,6 +127,7 @@ static ssize_t firmware_loading_show(struct device *dev, /** * firmware_loading_store - set value in the 'loading' control file * @dev: device pointer + * @attr: device attribute pointer * @buf: buffer to scan for loading control value * @count: number of bytes in @buf * diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 97f7f535f41..bb022ed4a86 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -30,8 +30,6 @@ new_skb(ulong len) skb->nh.raw = skb->mac.raw = skb->data; skb->protocol = __constant_htons(ETH_P_AOE); skb->priority = 0; - skb_put(skb, len); - memset(skb->head, 0, len); skb->next = skb->prev = NULL; /* tell the network layer not to perform IP checksums @@ -122,8 +120,8 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) skb = f->skb; h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - skb->len = sizeof *h + sizeof *ah; - memset(h, 0, ETH_ZLEN); + skb_put(skb, sizeof *h + sizeof *ah); + memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, h); f->waited = 0; f->buf = buf; @@ -149,7 +147,6 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) skb->len += bcnt; skb->data_len = bcnt; } else { - skb->len = ETH_ZLEN; writebit = 0; } @@ -206,6 +203,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) printk(KERN_INFO "aoe: skb alloc failure\n"); continue; } + skb_put(skb, sizeof *h + sizeof *ch); skb->dev = ifp; if (sl_tail == NULL) sl_tail = skb; @@ -243,6 +241,7 @@ freeframe(struct aoedev *d) continue; if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; + skb_trim(f->skb, 0); return f; } n++; @@ -698,8 +697,8 @@ aoecmd_ata_id(struct aoedev *d) skb = f->skb; h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - skb->len = ETH_ZLEN; - memset(h, 0, ETH_ZLEN); + skb_put(skb, sizeof *h + sizeof *ah); + memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, h); f->waited = 0; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d719a5d8f43..05dfe357527 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -225,6 +225,8 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, #include "cciss_scsi.c" /* For SCSI tape support */ +#define RAID_UNKNOWN 6 + #ifdef CONFIG_PROC_FS /* @@ -232,7 +234,6 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, */ #define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) -#define RAID_UNKNOWN 6 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", "UNKNOWN" }; @@ -1907,6 +1908,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, "does not support reading geometry\n"); drv->heads = 255; drv->sectors = 32; // Sectors per track + drv->raid_level = RAID_UNKNOWN; } else { drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; @@ -2491,7 +2493,7 @@ static void do_cciss_request(request_queue_t *q) c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = - (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; + (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE; c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7c95c762950..62462190e07 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -765,47 +765,34 @@ static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio */ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc) { - char sense[SCSI_SENSE_BUFFERSIZE]; - request_queue_t *q; + request_queue_t *q = bdev_get_queue(pd->bdev); struct request *rq; - DECLARE_COMPLETION_ONSTACK(wait); - int err = 0; + int ret = 0; - q = bdev_get_queue(pd->bdev); + rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? + WRITE : READ, __GFP_WAIT); + + if (cgc->buflen) { + if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT)) + goto out; + } + + rq->cmd_len = COMMAND_SIZE(rq->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 = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, - __GFP_WAIT); - rq->errors = 0; - rq->rq_disk = pd->bdev->bd_disk; - rq->bio = NULL; - rq->buffer = NULL; rq->timeout = 60*HZ; - rq->data = cgc->buffer; - rq->data_len = cgc->buflen; - rq->sense = sense; - memset(sense, 0, sizeof(sense)); - rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_HARDBARRIER; if (cgc->quiet) rq->cmd_flags |= REQ_QUIET; - 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->cmd_len = COMMAND_SIZE(rq->cmd[0]); - - rq->ref_count++; - rq->end_io_data = &wait; - rq->end_io = blk_end_sync_rq; - elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); - generic_unplug_device(q); - wait_for_completion(&wait); - - if (rq->errors) - err = -EIO; + blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0); + ret = rq->errors; +out: blk_put_request(rq); - return err; + return ret; } /* diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index e19ba4ebcd4..68592c33601 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -49,6 +49,7 @@ #include <asm/iseries/hv_lp_event.h> #include <asm/iseries/hv_lp_config.h> #include <asm/iseries/vio.h> +#include <asm/firmware.h> MODULE_DESCRIPTION("iSeries Virtual DASD"); MODULE_AUTHOR("Dave Boutcher"); @@ -769,6 +770,11 @@ static int __init viodasd_init(void) { int rc; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) { + rc = -ENODEV; + goto early_fail; + } + /* Try to open to our host lp */ if (viopath_hostLp == HvLpIndexInvalid) vio_set_hostlp(); diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index fdea58ae16b..6bdf593081d 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -117,15 +117,23 @@ static struct usb_device_id blacklist_ids[] = { /* IBM/Lenovo ThinkPad with Broadcom chip */ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU }, /* ANYCOM Bluetooth USB-200 and USB-250 */ { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, + /* HP laptop with Broadcom chip */ + { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_WRONG_SCO_MTU }, + + /* Dell laptop with Broadcom chip */ + { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_WRONG_SCO_MTU }, + /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, /* Kensington Bluetooth USB adapter */ { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, + { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_WRONG_SCO_MTU }, /* ISSC Bluetooth Adapter v3.1 */ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index e4a2f8f3a1d..3105dddf59f 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -337,6 +337,12 @@ static const char *mrw_address_space[] = { "DMA", "GAA" }; /* used in the audio ioctls */ #define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret +/* + * Another popular OS uses 7 seconds as the hard timeout for default + * commands, so it is a good choice for us as well. + */ +#define CDROM_DEF_TIMEOUT (7 * HZ) + /* Not-exported routines. */ static int open_for_data(struct cdrom_device_info * cdi); static int check_for_audio_disc(struct cdrom_device_info * cdi, @@ -1528,7 +1534,7 @@ void init_cdrom_command(struct packet_command *cgc, void *buf, int len, cgc->buffer = (char *) buf; cgc->buflen = len; cgc->data_direction = type; - cgc->timeout = 5*HZ; + cgc->timeout = CDROM_DEF_TIMEOUT; } /* DVD handling */ @@ -2139,8 +2145,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, cdi->last_sense = s->sense_key; } - rq->bio = bio; - if (blk_rq_unmap_user(rq)) + if (blk_rq_unmap_user(bio)) ret = -EFAULT; if (ret) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 54ca931e19e..93fbf84dcc4 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -47,6 +47,7 @@ #include <asm/iseries/hv_types.h> #include <asm/iseries/hv_lp_event.h> #include <asm/iseries/vio.h> +#include <asm/firmware.h> #define VIOCD_DEVICE "iseries/vcd" @@ -748,6 +749,9 @@ static int __init viocd_init(void) struct proc_dir_entry *e; int ret = 0; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + if (viopath_hostLp == HvLpIndexInvalid) { vio_set_hostlp(); /* If we don't have a host, bail out */ diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8b3317fd46c..1d59e2a5b9a 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -225,6 +225,10 @@ struct agp_bridge_data { #define I810_GMS_DISABLE 0x00000000 #define I810_PGETBL_CTL 0x2020 #define I810_PGETBL_ENABLED 0x00000001 +#define I965_PGETBL_SIZE_MASK 0x0000000e +#define I965_PGETBL_SIZE_512KB (0 << 1) +#define I965_PGETBL_SIZE_256KB (1 << 1) +#define I965_PGETBL_SIZE_128KB (2 << 1) #define I810_DRAM_CTL 0x3000 #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 51d0d562d01..c85c8cadb6d 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -101,6 +101,11 @@ static int amd_create_gatt_pages(int nr_tables) for (i = 0; i < nr_tables; i++) { entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL); if (entry == NULL) { + while (i > 0) { + kfree(tables[i-1]); + i--; + } + kfree(tables); retval = -ENOMEM; break; } diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 2f2c4efff8a..93d2209fee4 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -650,6 +650,15 @@ static struct pci_device_id agp_amd64_pci_table[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* VIA K8M890 / K8N890 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VT3336, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, /* VIA K8T890 */ { .class = (PCI_CLASS_BRIDGE_HOST << 8), diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index f244c668273..9987dc2e0c3 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -41,18 +41,18 @@ static struct gatt_mask ati_generic_masks[] = }; -typedef struct _ati_page_map { +struct ati_page_map { unsigned long *real; unsigned long __iomem *remapped; -} ati_page_map; +}; static struct _ati_generic_private { volatile u8 __iomem *registers; - ati_page_map **gatt_pages; + struct ati_page_map **gatt_pages; int num_tables; } ati_generic_private; -static int ati_create_page_map(ati_page_map *page_map) +static int ati_create_page_map(struct ati_page_map *page_map) { int i, err = 0; @@ -82,7 +82,7 @@ static int ati_create_page_map(ati_page_map *page_map) } -static void ati_free_page_map(ati_page_map *page_map) +static void ati_free_page_map(struct ati_page_map *page_map) { unmap_page_from_agp(virt_to_page(page_map->real)); iounmap(page_map->remapped); @@ -94,8 +94,8 @@ static void ati_free_page_map(ati_page_map *page_map) static void ati_free_gatt_pages(void) { int i; - ati_page_map **tables; - ati_page_map *entry; + struct ati_page_map **tables; + struct ati_page_map *entry; tables = ati_generic_private.gatt_pages; for (i = 0; i < ati_generic_private.num_tables; i++) { @@ -112,30 +112,30 @@ static void ati_free_gatt_pages(void) static int ati_create_gatt_pages(int nr_tables) { - ati_page_map **tables; - ati_page_map *entry; + struct ati_page_map **tables; + struct ati_page_map *entry; int retval = 0; int i; - tables = kzalloc((nr_tables + 1) * sizeof(ati_page_map *),GFP_KERNEL); + tables = kzalloc((nr_tables + 1) * sizeof(struct ati_page_map *),GFP_KERNEL); if (tables == NULL) return -ENOMEM; for (i = 0; i < nr_tables; i++) { - entry = kzalloc(sizeof(ati_page_map), GFP_KERNEL); + entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL); if (entry == NULL) { - while (i>0) { - kfree (tables[i-1]); + while (i > 0) { + kfree(tables[i-1]); i--; } - kfree (tables); - tables = NULL; + kfree(tables); retval = -ENOMEM; break; } tables[i] = entry; retval = ati_create_page_map(entry); - if (retval != 0) break; + if (retval != 0) + break; } ati_generic_private.num_tables = nr_tables; ati_generic_private.gatt_pages = tables; @@ -340,7 +340,7 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, static int ati_create_gatt_table(struct agp_bridge_data *bridge) { struct aper_size_info_lvl2 *value; - ati_page_map page_dir; + struct ati_page_map page_dir; unsigned long addr; int retval; u32 temp; @@ -400,7 +400,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge) static int ati_free_gatt_table(struct agp_bridge_data *bridge) { - ati_page_map page_dir; + struct ati_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 883a36a2783..3491d6f84bc 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -965,6 +965,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) if (!bridge) return -EINVAL; + if (mem->page_count == 0) + return 0; + temp = bridge->current_size; switch (bridge->driver->size_type) { @@ -1016,8 +1019,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j); - readl(bridge->gatt_table+j); /* PCI Posting. */ } + readl(bridge->gatt_table+j-1); /* PCI Posting. */ bridge->driver->tlb_flush(mem); return 0; @@ -1034,6 +1037,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) if (!bridge) return -EINVAL; + if (mem->page_count == 0) + return 0; + if (type != 0 || mem->type != 0) { /* The generic routines know nothing of memory types */ return -EINVAL; @@ -1042,10 +1048,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) /* AK: bogus, should encode addresses > 4GB */ for (i = pg_start; i < (mem->page_count + pg_start); i++) { writel(bridge->scratch_page, bridge->gatt_table+i); - readl(bridge->gatt_table+i); /* PCI Posting. */ } + readl(bridge->gatt_table+i-1); /* PCI Posting. */ - global_cache_flush(); bridge->driver->tlb_flush(mem); return 0; } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 555b3a8ab49..a3011de51f7 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -207,6 +207,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int i, j, num_entries; void *temp; + if (mem->page_count == 0) + return 0; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -221,12 +224,16 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, if (type != 0 || mem->type != 0) { if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) { /* special insert */ - global_cache_flush(); + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + for (i = pg_start; i < (pg_start + mem->page_count); i++) { writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } - global_cache_flush(); + readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ + agp_bridge->driver->tlb_flush(mem); return 0; } @@ -236,14 +243,17 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, } insert: - global_cache_flush(); + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), intel_i810_private.registers+I810_PTE_BASE+(j*4)); - readl(intel_i810_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */ } - global_cache_flush(); + readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */ agp_bridge->driver->tlb_flush(mem); return 0; @@ -254,12 +264,14 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, { int i; + if (mem->page_count == 0) + return 0; + for (i = pg_start; i < (mem->page_count + pg_start); i++) { writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } + readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -370,6 +382,11 @@ static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ volatile u8 __iomem *registers; volatile u32 __iomem *gtt; /* I915G */ + /* gtt_entries is the number of gtt entries that are already mapped + * to stolen memory. Stolen memory is larger than the memory mapped + * through gtt_entries, as it includes some reserved space for the BIOS + * popup and for the GTT. + */ int gtt_entries; } intel_i830_private; @@ -380,14 +397,41 @@ static void intel_i830_init_gtt_entries(void) u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; - int size; + int size; /* reserved space (in kb) at the top of stolen memory */ pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); - /* We obtain the size of the GTT, which is also stored (for some - * reason) at the top of stolen memory. Then we add 4KB to that - * for the video BIOS popup, which is also stored in there. */ - size = agp_bridge->driver->fetch_size() + 4; + if (IS_I965) { + u32 pgetbl_ctl; + + pci_read_config_dword(agp_bridge->dev, I810_PGETBL_CTL, + &pgetbl_ctl); + /* The 965 has a field telling us the size of the GTT, + * which may be larger than what is necessary to map the + * aperture. + */ + switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { + case I965_PGETBL_SIZE_128KB: + size = 128; + break; + case I965_PGETBL_SIZE_256KB: + size = 256; + break; + case I965_PGETBL_SIZE_512KB: + size = 512; + break; + default: + printk(KERN_INFO PFX "Unknown page table size, " + "assuming 512KB\n"); + size = 512; + } + size += 4; /* add in BIOS popup space */ + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + size = agp_bridge->driver->fetch_size() + 4; + } if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { @@ -576,6 +620,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int int i,j,num_entries; void *temp; + if (mem->page_count == 0) + return 0; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -598,16 +645,18 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) return -EINVAL; - global_cache_flush(); /* FIXME: Necessary ?*/ + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), intel_i830_private.registers+I810_PTE_BASE+(j*4)); - readl(intel_i830_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */ } + readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4)); - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -617,7 +666,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, { int i; - global_cache_flush(); + if (mem->page_count == 0) + return 0; if (pg_start < intel_i830_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); @@ -626,10 +676,9 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, for (i = pg_start; i < (mem->page_count + pg_start); i++) { writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } + readl(intel_i830_private.registers+I810_PTE_BASE+((i-1)*4)); - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -686,6 +735,9 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, int i,j,num_entries; void *temp; + if (mem->page_count == 0) + return 0; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -708,15 +760,17 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) return -EINVAL; - global_cache_flush(); + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), intel_i830_private.gtt+j); - readl(intel_i830_private.gtt+j); /* PCI Posting. */ } + readl(intel_i830_private.gtt+j-1); - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -726,7 +780,8 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, { int i; - global_cache_flush(); + if (mem->page_count == 0) + return 0; if (pg_start < intel_i830_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); @@ -735,30 +790,34 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, for (i = pg_start; i < (mem->page_count + pg_start); i++) { writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); - readl(intel_i830_private.gtt+i); } + readl(intel_i830_private.gtt+i-1); - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } -static int intel_i915_fetch_size(void) +/* Return the aperture size by just checking the resource length. The effect + * described in the spec of the MSAC registers is just changing of the + * resource size. + */ +static int intel_i9xx_fetch_size(void) { - struct aper_size_info_fixed *values; - u32 temp, offset; + int num_sizes = sizeof(intel_i830_sizes) / sizeof(*intel_i830_sizes); + int aper_size; /* size in megabytes */ + int i; -#define I915_256MB_ADDRESS_MASK (1<<27) + aper_size = pci_resource_len(intel_i830_private.i830_dev, 2) / MB(1); - values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); + for (i = 0; i < num_sizes; i++) { + if (aper_size == intel_i830_sizes[i].size) { + agp_bridge->current_size = intel_i830_sizes + i; + agp_bridge->previous_size = agp_bridge->current_size; + return aper_size; + } + } - pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp); - if (temp & I915_256MB_ADDRESS_MASK) - offset = 0; /* 128MB aperture */ - else - offset = 2; /* 256MB aperture */ - agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); - return values[offset].size; + return 0; } /* The intel i915 automatically initializes the agp aperture during POST. @@ -821,40 +880,9 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } -static int intel_i965_fetch_size(void) -{ - struct aper_size_info_fixed *values; - u32 offset = 0; - u8 temp; - -#define I965_512MB_ADDRESS_MASK (3<<1) - - values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); - - pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp); - temp &= I965_512MB_ADDRESS_MASK; - switch (temp) { - case 0x00: - offset = 0; /* 128MB */ - break; - case 0x06: - offset = 3; /* 512MB */ - break; - default: - case 0x02: - offset = 2; /* 256MB */ - break; - } - - agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); - - /* The i965 GTT is always sized as if it had a 512kB aperture size */ - return 512; -} - /* The intel i965 automatically initializes the agp aperture during POST. -+ * Use the memory already set aside for in the GTT. -+ */ + * Use the memory already set aside for in the GTT. + */ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) { int page_order; @@ -1574,7 +1602,7 @@ static struct agp_bridge_driver intel_915_driver = { .num_aperture_sizes = 4, .needs_scratch_page = TRUE, .configure = intel_i915_configure, - .fetch_size = intel_i915_fetch_size, + .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .tlb_flush = intel_i810_tlbflush, .mask_memory = intel_i810_mask_memory, @@ -1598,7 +1626,7 @@ static struct agp_bridge_driver intel_i965_driver = { .num_aperture_sizes = 4, .needs_scratch_page = TRUE, .configure = intel_i915_configure, - .fetch_size = intel_i965_fetch_size, + .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .tlb_flush = intel_i810_tlbflush, .mask_memory = intel_i965_mask_memory, @@ -1927,6 +1955,15 @@ static int agp_intel_resume(struct pci_dev *pdev) pci_restore_state(pdev); + /* We should restore our graphics device's config space, + * as host bridge (00:00) resumes before graphics device (02:00), + * then our access to its pci space can work right. + */ + if (intel_i810_private.i810_dev) + pci_restore_state(intel_i810_private.i810_dev); + if (intel_i830_private.i830_dev) + pci_restore_state(intel_i830_private.i830_dev); + if (bridge->driver == &intel_generic_driver) intel_configure(); else if (bridge->driver == &intel_850_driver) diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index d73be4c2db8..902648db7ef 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -281,10 +281,11 @@ static int __devinit agp_sgi_init(void) else return 0; - sgi_tioca_agp_bridges = - (struct agp_bridge_data **)kmalloc(tioca_gart_found * - sizeof(struct agp_bridge_data *), - GFP_KERNEL); + sgi_tioca_agp_bridges = kmalloc(tioca_gart_found * + sizeof(struct agp_bridge_data *), + GFP_KERNEL); + if (!sgi_tioca_agp_bridges) + return -ENOMEM; j = 0; list_for_each_entry(info, &tioca_list, ca_list) { diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index c149ac9ce9a..2ded7a280d7 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -380,9 +380,23 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata = /* P4M800CE */ { .device_id = PCI_DEVICE_ID_VIA_P4M800CE, - .chipset_name = "P4M800CE", + .chipset_name = "VT3314", + }, + /* CX700 */ + { + .device_id = PCI_DEVICE_ID_VIA_CX700, + .chipset_name = "CX700", + }, + /* VT3336 */ + { + .device_id = PCI_DEVICE_ID_VIA_VT3336, + .chipset_name = "VT3336", + }, + /* P4M890 */ + { + .device_id = PCI_DEVICE_ID_VIA_P4M890, + .chipset_name = "P4M890", }, - { }, /* dummy final entry, always present */ }; @@ -524,6 +538,9 @@ static const struct pci_device_id agp_via_pci_table[] = { ID(PCI_DEVICE_ID_VIA_83_87XX_1), ID(PCI_DEVICE_ID_VIA_3296_0), ID(PCI_DEVICE_ID_VIA_P4M800CE), + ID(PCI_DEVICE_ID_VIA_CX700), + ID(PCI_DEVICE_ID_VIA_VT3336), + ID(PCI_DEVICE_ID_VIA_P4M890), { } }; diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 0bbb04f2390..6dcdceb8120 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -561,8 +561,7 @@ struct drm_driver { int (*context_dtor) (struct drm_device * dev, int context); int (*kernel_context_switch) (struct drm_device * dev, int old, int new); - void (*kernel_context_switch_unlock) (struct drm_device * dev, - drm_lock_t *lock); + void (*kernel_context_switch_unlock) (struct drm_device * dev); int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence); int (*dri_library_name) (struct drm_device *dev, char *buf); @@ -1143,9 +1142,5 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area); extern unsigned long drm_core_get_map_ofs(drm_map_t * map); extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); -#ifndef pci_pretty_name -#define pci_pretty_name(dev) "" -#endif - #endif /* __KERNEL__ */ #endif diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index 116ed0f2ac0..e9993ba461a 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -182,7 +182,7 @@ int drm_unlock(struct inode *inode, struct file *filp, * modules but is required by the Sparc driver. */ if (dev->driver->kernel_context_switch_unlock) - dev->driver->kernel_context_switch_unlock(dev, &lock); + dev->driver->kernel_context_switch_unlock(dev); else { drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 5fd6dc0870c..120d10256fe 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -211,14 +211,16 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if (!dev) return -ENOMEM; - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret) + goto err_g1; if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); - goto err_g1; + goto err_g2; } if ((ret = drm_get_head(dev, &dev->primary))) - goto err_g1; + goto err_g2; DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, @@ -226,7 +228,9 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, return 0; - err_g1: +err_g2: + pci_disable_device(pdev); +err_g1: drm_free(dev, sizeof(*dev), DRM_MEM_STUB); return ret; } diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index ba4b8de83cf..cc8e2ebe128 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -45,8 +45,8 @@ struct class *drm_sysfs_create(struct module *owner, char *name) int err; class = class_create(owner, name); - if (!class) { - err = -ENOMEM; + if (IS_ERR(class)) { + err = PTR_ERR(class); goto err_out; } @@ -113,8 +113,8 @@ struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head) MKDEV(DRM_MAJOR, head->minor), &(head->dev->pdev)->dev, "card%d", head->minor); - if (!class_dev) { - err = -ENOMEM; + if (IS_ERR(class_dev)) { + err = PTR_ERR(class_dev); goto err_out; } diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index e5463b111fc..78c1ae28f17 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -46,88 +46,167 @@ static void i915_vblank_tasklet(drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - struct list_head *list, *tmp; + struct list_head *list, *tmp, hits, *hit; + int nhits, nrects, slice[2], upper[2], lower[2], i; + unsigned counter[2] = { atomic_read(&dev->vbl_received), + atomic_read(&dev->vbl_received2) }; + drm_drawable_info_t *drw; + drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + u32 cpp = dev_priv->cpp; + u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB) + : XY_SRC_COPY_BLT_CMD; + u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | + (cpp << 23) | (1 << 24); + RING_LOCALS; DRM_DEBUG("\n"); + INIT_LIST_HEAD(&hits); + + nhits = nrects = 0; + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + /* Find buffer swaps scheduled for this vertical blank */ list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { drm_i915_vbl_swap_t *vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); - atomic_t *counter = vbl_swap->pipe ? &dev->vbl_received2 : - &dev->vbl_received; - - if ((atomic_read(counter) - vbl_swap->sequence) <= (1<<23)) { - drm_drawable_info_t *drw; - - spin_unlock(&dev_priv->swaps_lock); - - spin_lock(&dev->drw_lock); - - drw = drm_get_drawable_info(dev, vbl_swap->drw_id); - - if (drw) { - int i, num_rects = drw->num_rects; - drm_clip_rect_t *rect = drw->rects; - drm_i915_sarea_t *sarea_priv = - dev_priv->sarea_priv; - u32 cpp = dev_priv->cpp; - u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | - XY_SRC_COPY_BLT_WRITE_ALPHA | - XY_SRC_COPY_BLT_WRITE_RGB) - : XY_SRC_COPY_BLT_CMD; - u32 pitchropcpp = (sarea_priv->pitch * cpp) | - (0xcc << 16) | (cpp << 23) | - (1 << 24); - RING_LOCALS; - - i915_kernel_lost_context(dev); - - BEGIN_LP_RING(6); - - OUT_RING(GFX_OP_DRAWRECT_INFO); - OUT_RING(0); - OUT_RING(0); - OUT_RING(sarea_priv->width | - sarea_priv->height << 16); - OUT_RING(sarea_priv->width | - sarea_priv->height << 16); - OUT_RING(0); - ADVANCE_LP_RING(); + if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) + continue; + + list_del(list); + dev_priv->swaps_pending--; - sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + spin_unlock(&dev_priv->swaps_lock); + spin_lock(&dev->drw_lock); - for (i = 0; i < num_rects; i++, rect++) { - BEGIN_LP_RING(8); + drw = drm_get_drawable_info(dev, vbl_swap->drw_id); + + if (!drw) { + spin_unlock(&dev->drw_lock); + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + spin_lock(&dev_priv->swaps_lock); + continue; + } - OUT_RING(cmd); - OUT_RING(pitchropcpp); - OUT_RING((rect->y1 << 16) | rect->x1); - OUT_RING((rect->y2 << 16) | rect->x2); - OUT_RING(sarea_priv->front_offset); - OUT_RING((rect->y1 << 16) | rect->x1); - OUT_RING(pitchropcpp & 0xffff); - OUT_RING(sarea_priv->back_offset); + list_for_each(hit, &hits) { + drm_i915_vbl_swap_t *swap_cmp = + list_entry(hit, drm_i915_vbl_swap_t, head); + drm_drawable_info_t *drw_cmp = + drm_get_drawable_info(dev, swap_cmp->drw_id); - ADVANCE_LP_RING(); - } + if (drw_cmp && + drw_cmp->rects[0].y1 > drw->rects[0].y1) { + list_add_tail(list, hit); + break; } + } - spin_unlock(&dev->drw_lock); + spin_unlock(&dev->drw_lock); - spin_lock(&dev_priv->swaps_lock); + /* List of hits was empty, or we reached the end of it */ + if (hit == &hits) + list_add_tail(list, hits.prev); - list_del(list); + nhits++; - drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + spin_lock(&dev_priv->swaps_lock); + } + + if (nhits == 0) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + return; + } + + spin_unlock(&dev_priv->swaps_lock); - dev_priv->swaps_pending--; + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(6); + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(sarea_priv->width | sarea_priv->height << 16); + OUT_RING(sarea_priv->width | sarea_priv->height << 16); + OUT_RING(0); + + ADVANCE_LP_RING(); + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + upper[0] = upper[1] = 0; + slice[0] = max(sarea_priv->pipeA_h / nhits, 1); + slice[1] = max(sarea_priv->pipeB_h / nhits, 1); + lower[0] = sarea_priv->pipeA_y + slice[0]; + lower[1] = sarea_priv->pipeB_y + slice[0]; + + spin_lock(&dev->drw_lock); + + /* Emit blits for buffer swaps, partitioning both outputs into as many + * slices as there are buffer swaps scheduled in order to avoid tearing + * (based on the assumption that a single buffer swap would always + * complete before scanout starts). + */ + for (i = 0; i++ < nhits; + upper[0] = lower[0], lower[0] += slice[0], + upper[1] = lower[1], lower[1] += slice[1]) { + if (i == nhits) + lower[0] = lower[1] = sarea_priv->height; + + list_for_each(hit, &hits) { + drm_i915_vbl_swap_t *swap_hit = + list_entry(hit, drm_i915_vbl_swap_t, head); + drm_clip_rect_t *rect; + int num_rects, pipe; + unsigned short top, bottom; + + drw = drm_get_drawable_info(dev, swap_hit->drw_id); + + if (!drw) + continue; + + rect = drw->rects; + pipe = swap_hit->pipe; + top = upper[pipe]; + bottom = lower[pipe]; + + for (num_rects = drw->num_rects; num_rects--; rect++) { + int y1 = max(rect->y1, top); + int y2 = min(rect->y2, bottom); + + if (y1 >= y2) + continue; + + BEGIN_LP_RING(8); + + OUT_RING(cmd); + OUT_RING(pitchropcpp); + OUT_RING((y1 << 16) | rect->x1); + OUT_RING((y2 << 16) | rect->x2); + OUT_RING(sarea_priv->front_offset); + OUT_RING((y1 << 16) | rect->x1); + OUT_RING(pitchropcpp & 0xffff); + OUT_RING(sarea_priv->back_offset); + + ADVANCE_LP_RING(); + } } } - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + list_for_each_safe(hit, tmp, &hits) { + drm_i915_vbl_swap_t *swap_hit = + list_entry(hit, drm_i915_vbl_swap_t, head); + + list_del(hit); + + drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER); + } } irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) @@ -421,7 +500,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (!drm_get_drawable_info(dev, swap.drawable)) { spin_unlock_irqrestore(&dev->drw_lock, irqflags); - DRM_ERROR("Invalid drawable ID %d\n", swap.drawable); + DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable); return DRM_ERR(EINVAL); } diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h index 5d835b006f5..6e8af313f2b 100644 --- a/drivers/char/drm/r128_drm.h +++ b/drivers/char/drm/r128_drm.h @@ -1,7 +1,8 @@ /* r128_drm.h -- Public header for the r128 driver -*- linux-c -*- * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com */ -/* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. +/* + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. * diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 94abffb2cca..f1efb49de8d 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -1,7 +1,8 @@ /* r128_drv.h -- Private header for r128 driver -*- linux-c -*- * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com */ -/* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. * diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index a080cdd6081..17b11e7d8f3 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -1,7 +1,8 @@ /* r128_state.c -- State support for r128 -*- linux-c -*- * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com */ -/* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. +/* + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index d14477ba367..032a022ec6a 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -242,26 +242,6 @@ static __inline__ int r300_check_range(unsigned reg, int count) return 0; } -/* - * we expect offsets passed to the framebuffer to be either within video - * memory or within AGP space - */ -static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, - u32 offset) -{ - /* we realy want to check against end of video aperture - but this value is not being kept. - This code is correct for now (does the same thing as the - code that sets MC_FB_LOCATION) in radeon_cp.c */ - if (offset >= dev_priv->fb_location && - offset < (dev_priv->fb_location + dev_priv->fb_size)) - return 0; - if (offset >= dev_priv->gart_vm_start && - offset < (dev_priv->gart_vm_start + dev_priv->gart_size)) - return 0; - return 1; -} - static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * dev_priv, drm_radeon_kcmd_buffer_t @@ -290,7 +270,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * case MARK_SAFE: break; case MARK_CHECK_OFFSET: - if (r300_check_offset(dev_priv, (u32) values[i])) { + if (!radeon_check_offset(dev_priv, (u32) values[i])) { DRM_ERROR ("Offset failed range check (reg=%04x sz=%d)\n", reg, sz); @@ -452,7 +432,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, i = 1; while ((k < narrays) && (i < (count + 1))) { i++; /* skip attribute field */ - if (r300_check_offset(dev_priv, payload[i])) { + if (!radeon_check_offset(dev_priv, payload[i])) { DRM_ERROR ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i); @@ -463,7 +443,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, if (k == narrays) break; /* have one more to process, they come in pairs */ - if (r300_check_offset(dev_priv, payload[i])) { + if (!radeon_check_offset(dev_priv, payload[i])) { DRM_ERROR ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", k, i); @@ -508,7 +488,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[2] << 10; - ret = r300_check_offset(dev_priv, offset); + ret = !radeon_check_offset(dev_priv, offset); if (ret) { DRM_ERROR("Invalid bitblt first offset is %08X\n", offset); return DRM_ERR(EINVAL); @@ -518,7 +498,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) && (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[3] << 10; - ret = r300_check_offset(dev_priv, offset); + ret = !radeon_check_offset(dev_priv, offset); if (ret) { DRM_ERROR("Invalid bitblt second offset is %08X\n", offset); return DRM_ERR(EINVAL); @@ -551,7 +531,7 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); return DRM_ERR(EINVAL); } - ret = r300_check_offset(dev_priv, cmd[2]); + ret = !radeon_check_offset(dev_priv, cmd[2]); if (ret) { DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); return DRM_ERR(EINVAL); diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index f45cd7f147a..8b105f1460a 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -303,6 +303,21 @@ extern int radeon_no_wb; extern drm_ioctl_desc_t radeon_ioctls[]; extern int radeon_max_ioctl; +/* Check whether the given hardware address is inside the framebuffer or the + * GART area. + */ +static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv, + u64 off) +{ + u32 fb_start = dev_priv->fb_location; + u32 fb_end = fb_start + dev_priv->fb_size - 1; + u32 gart_start = dev_priv->gart_vm_start; + u32 gart_end = gart_start + dev_priv->gart_size - 1; + + return ((off >= fb_start && off <= fb_end) || + (off >= gart_start && off <= gart_end)); +} + /* radeon_cp.c */ extern int radeon_cp_init(DRM_IOCTL_ARGS); extern int radeon_cp_start(DRM_IOCTL_ARGS); diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index d60519de887..3ff0baa2fbf 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -1,5 +1,5 @@ -/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- - * +/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */ +/* * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * * The Weather Channel (TM) funded Tungsten Graphics to develop the diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c index 030a6fad0d8..517cad8b6e3 100644 --- a/drivers/char/drm/radeon_mem.c +++ b/drivers/char/drm/radeon_mem.c @@ -1,5 +1,5 @@ -/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- - * +/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */ +/* * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * * The Weather Channel (TM) funded Tungsten Graphics to develop the diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 6e04fdd732a..938eccb78cc 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -43,10 +43,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * u32 *offset) { u64 off = *offset; - u32 fb_start = dev_priv->fb_location; - u32 fb_end = fb_start + dev_priv->fb_size - 1; - u32 gart_start = dev_priv->gart_vm_start; - u32 gart_end = gart_start + dev_priv->gart_size - 1; + u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1; struct drm_radeon_driver_file_fields *radeon_priv; /* Hrm ... the story of the offset ... So this function converts @@ -66,8 +63,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * /* First, the best case, the offset already lands in either the * framebuffer or the GART mapped space */ - if ((off >= fb_start && off <= fb_end) || - (off >= gart_start && off <= gart_end)) + if (radeon_check_offset(dev_priv, off)) return 0; /* Ok, that didn't happen... now check if we have a zero based @@ -81,11 +77,10 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * /* Finally, assume we aimed at a GART offset if beyond the fb */ if (off > fb_end) - off = off - fb_end - 1 + gart_start; + off = off - fb_end - 1 + dev_priv->gart_vm_start; /* Now recheck and fail if out of bounds */ - if ((off >= fb_start && off <= fb_end) || - (off >= gart_start && off <= gart_end)) { + if (radeon_check_offset(dev_priv, off)) { DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); *offset = off; return 0; diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index a9a84f88df5..b94fab55680 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -963,8 +963,8 @@ static int savage_bci_event_emit(DRM_IOCTL_ARGS) event.count = savage_bci_emit_event(dev_priv, event.flags); event.count |= dev_priv->event_wrap << 16; - DRM_COPY_TO_USER_IOCTL(&((drm_savage_event_emit_t __user *) data)-> - count, event.count, sizeof(event.count)); + DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data, + event, sizeof(event)); return 0; } diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 71e4e0f3fd5..556fd81fa81 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -144,7 +144,7 @@ static void __exit mod_exit(void) hwrng_unregister(&amd_rng); } -subsys_initcall(mod_init); +module_init(mod_init); module_exit(mod_exit); MODULE_AUTHOR("The Linux Kernel team"); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index d37ced0d132..8e8658dcd2e 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -125,7 +125,7 @@ static void __exit mod_exit(void) iounmap(mem); } -subsys_initcall(mod_init); +module_init(mod_init); module_exit(mod_exit); MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 8efbc9c0e54..f22e78e3c70 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -143,6 +143,11 @@ static const struct pci_device_id pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, pci_tbl); +static __initdata int no_fwh_detect; +module_param(no_fwh_detect, int, 0); +MODULE_PARM_DESC(no_fwh_detect, "Skip FWH detection:\n" + " positive value - skip if FWH space locked read-only\n" + " negative value - skip always"); static inline u8 hwstatus_get(void __iomem *mem) { @@ -240,6 +245,11 @@ static int __init mod_init(void) if (!dev) goto out; /* Device not found. */ + if (no_fwh_detect < 0) { + pci_dev_put(dev); + goto fwh_done; + } + /* Check for Intel 82802 */ if (dev->device < 0x2640) { fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD; @@ -252,6 +262,23 @@ static int __init mod_init(void) pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val); pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val); + if ((bios_cntl_val & + (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) + == BIOS_CNTL_LOCK_ENABLE_MASK) { + static __initdata /*const*/ char warning[] = + KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n" + KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n" + KERN_WARNING PFX "you are certain that your system has a functional\n" + KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n"; + + pci_dev_put(dev); + if (no_fwh_detect) + goto fwh_done; + printk(warning); + err = -EBUSY; + goto out; + } + mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); if (mem == NULL) { pci_dev_put(dev); @@ -280,8 +307,7 @@ static int __init mod_init(void) pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val | FWH_F8_EN_MASK); - if (!(bios_cntl_val & - (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) + if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK)) pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK); @@ -315,6 +341,8 @@ static int __init mod_init(void) goto out; } +fwh_done: + err = -ENOMEM; mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); if (!mem) @@ -350,7 +378,7 @@ static void __exit mod_exit(void) iounmap(mem); } -subsys_initcall(mod_init); +module_init(mod_init); module_exit(mod_exit); MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets"); diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index c9caff57db8..bab43ca32ac 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -64,7 +64,7 @@ static void __exit ixp4xx_rng_exit(void) iounmap(rng_base); } -subsys_initcall(ixp4xx_rng_init); +module_init(ixp4xx_rng_init); module_exit(ixp4xx_rng_exit); MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 0e786b617bb..9ebf84d1865 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -176,7 +176,7 @@ static void __exit mod_exit(void) hwrng_unregister(&via_rng); } -subsys_initcall(mod_init); +module_init(mod_init); module_exit(mod_exit); MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets"); diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h index 5eabe47b0bc..433305062fb 100644 --- a/drivers/char/ip2/i2ellis.h +++ b/drivers/char/ip2/i2ellis.h @@ -606,9 +606,9 @@ static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int); // code and returning. // #define COMPLETE(pB,code) \ - if(1){ \ + do { \ pB->i2eError = code; \ return (code == I2EE_GOOD);\ - } + } while (0) #endif // I2ELLIS_H diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 4e4691a5389..53582b53da9 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3649,8 +3649,6 @@ static void ipmi_timeout_handler(long timeout_period) unsigned long flags; int i; - INIT_LIST_HEAD(&timeouts); - rcu_read_lock(); list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { /* See if any waiting messages need to be processed. */ @@ -3671,6 +3669,7 @@ static void ipmi_timeout_handler(long timeout_period) /* 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++) check_msg_timeout(intf, &(intf->seq_table[i]), diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 78280380a90..6b634e8d951 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -216,13 +216,13 @@ static int set_param_str(const char *val, struct kernel_param *kp) { action_fn fn = (action_fn) kp->arg; int rv = 0; - char *dup, *s; + char valcp[16]; + char *s; - dup = kstrdup(val, GFP_KERNEL); - if (!dup) - return -ENOMEM; + strncpy(valcp, val, 16); + valcp[15] = '\0'; - s = strstrip(dup); + s = strstrip(valcp); down_read(®ister_sem); rv = fn(s, NULL); @@ -235,7 +235,6 @@ static int set_param_str(const char *val, struct kernel_param *kp) out_unlock: up_read(®ister_sem); - kfree(dup); return rv; } diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 5a747e68599..01084abffdd 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -230,6 +230,20 @@ static struct isi_port isi_ports[PORT_COUNT]; * it wants to talk. */ +static inline int WaitTillCardIsFree(u16 base) +{ + unsigned int count = 0; + unsigned int a = in_atomic(); /* do we run under spinlock? */ + + while (!(inw(base + 0xe) & 0x1) && count++ < 100) + if (a) + mdelay(1); + else + msleep(1); + + return !(inw(base + 0xe) & 0x1); +} + static int lock_card(struct isi_board *card) { char retries; @@ -276,69 +290,71 @@ static void unlock_card(struct isi_board *card) * ISI Card specific ops ... */ +/* card->lock HAS to be held */ static void raise_dtr(struct isi_port *port) { struct isi_board *card = port->card; unsigned long base = card->base; u16 channel = port->channel; - if (!lock_card(card)) + if (WaitTillCardIsFree(base)) return; outw(0x8000 | (channel << card->shift_count) | 0x02, base); outw(0x0504, base); InterruptTheCard(base); port->status |= ISI_DTR; - unlock_card(card); } +/* card->lock HAS to be held */ static inline void drop_dtr(struct isi_port *port) { struct isi_board *card = port->card; unsigned long base = card->base; u16 channel = port->channel; - if (!lock_card(card)) + if (WaitTillCardIsFree(base)) return; outw(0x8000 | (channel << card->shift_count) | 0x02, base); outw(0x0404, base); InterruptTheCard(base); port->status &= ~ISI_DTR; - unlock_card(card); } +/* card->lock HAS to be held */ static inline void raise_rts(struct isi_port *port) { struct isi_board *card = port->card; unsigned long base = card->base; u16 channel = port->channel; - if (!lock_card(card)) + if (WaitTillCardIsFree(base)) return; outw(0x8000 | (channel << card->shift_count) | 0x02, base); outw(0x0a04, base); InterruptTheCard(base); port->status |= ISI_RTS; - unlock_card(card); } + +/* card->lock HAS to be held */ static inline void drop_rts(struct isi_port *port) { struct isi_board *card = port->card; unsigned long base = card->base; u16 channel = port->channel; - if (!lock_card(card)) + if (WaitTillCardIsFree(base)) return; outw(0x8000 | (channel << card->shift_count) | 0x02, base); outw(0x0804, base); InterruptTheCard(base); port->status &= ~ISI_RTS; - unlock_card(card); } +/* card->lock MUST NOT be held */ static inline void raise_dtr_rts(struct isi_port *port) { struct isi_board *card = port->card; @@ -355,35 +371,20 @@ static inline void raise_dtr_rts(struct isi_port *port) unlock_card(card); } +/* card->lock HAS to be held */ static void drop_dtr_rts(struct isi_port *port) { struct isi_board *card = port->card; unsigned long base = card->base; u16 channel = port->channel; - if (!lock_card(card)) + if (WaitTillCardIsFree(base)) return; outw(0x8000 | (channel << card->shift_count) | 0x02, base); outw(0x0c04, base); InterruptTheCard(base); port->status &= ~(ISI_RTS | ISI_DTR); - unlock_card(card); -} - -static inline void kill_queue(struct isi_port *port, short queue) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (!lock_card(card)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw((queue << 8) | 0x06, base); - InterruptTheCard(base); - unlock_card(card); } /* @@ -744,7 +745,7 @@ static void isicom_config_port(struct isi_port *port) else raise_dtr(port); - if (lock_card(card)) { + if (WaitTillCardIsFree(base) == 0) { outw(0x8000 | (channel << shift_count) |0x03, base); outw(linuxb_to_isib[baud] << 8 | 0x03, base); channel_setup = 0; @@ -772,7 +773,6 @@ static void isicom_config_port(struct isi_port *port) } outw(channel_setup, base); InterruptTheCard(base); - unlock_card(card); } if (C_CLOCAL(tty)) port->flags &= ~ASYNC_CHECK_CD; @@ -791,12 +791,11 @@ static void isicom_config_port(struct isi_port *port) if (I_IXOFF(tty)) flow_ctrl |= ISICOM_INITIATE_XONXOFF; - if (lock_card(card)) { + if (WaitTillCardIsFree(base) == 0) { outw(0x8000 | (channel << shift_count) |0x04, base); outw(flow_ctrl << 8 | 0x05, base); outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); InterruptTheCard(base); - unlock_card(card); } /* rx enabled -> enable port for rx on the card */ @@ -821,10 +820,9 @@ static inline void isicom_setup_board(struct isi_board *bp) } port = bp->ports; bp->status |= BOARD_ACTIVE; - spin_unlock_irqrestore(&bp->card_lock, flags); for (channel = 0; channel < bp->port_count; channel++, port++) drop_dtr_rts(port); - return; + spin_unlock_irqrestore(&bp->card_lock, flags); } static int isicom_setup_port(struct isi_port *port) @@ -857,7 +855,12 @@ static int isicom_setup_port(struct isi_port *port) port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; /* discard any residual data */ - kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX); + if (WaitTillCardIsFree(card->base) == 0) { + outw(0x8000 | (port->channel << card->shift_count) | 0x02, + card->base); + outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); + InterruptTheCard(card->base); + } isicom_config_port(port); port->flags |= ASYNC_INITIALIZED; @@ -983,28 +986,22 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) static inline void isicom_shutdown_board(struct isi_board *bp) { - unsigned long flags; - - spin_lock_irqsave(&bp->card_lock, flags); if (bp->status & BOARD_ACTIVE) { bp->status &= ~BOARD_ACTIVE; } - spin_unlock_irqrestore(&bp->card_lock, flags); } +/* card->lock HAS to be held */ static void isicom_shutdown_port(struct isi_port *port) { struct isi_board *card = port->card; struct tty_struct *tty; - unsigned long flags; tty = port->tty; - spin_lock_irqsave(&card->card_lock, flags); - if (!(port->flags & ASYNC_INITIALIZED)) { - spin_unlock_irqrestore(&card->card_lock, flags); + if (!(port->flags & ASYNC_INITIALIZED)) return; - } + if (port->xmit_buf) { free_page((unsigned long) port->xmit_buf); port->xmit_buf = NULL; @@ -1012,7 +1009,6 @@ static void isicom_shutdown_port(struct isi_port *port) port->flags &= ~ASYNC_INITIALIZED; /* 3rd October 2000 : Vinayak P Risbud */ port->tty = NULL; - spin_unlock_irqrestore(&card->card_lock, flags); /*Fix done by Anil .S on 30-04-2001 remote login through isi port has dtr toggle problem @@ -1258,10 +1254,12 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct isi_port *port = tty->driver_data; + unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; + spin_lock_irqsave(&port->card->card_lock, flags); if (set & TIOCM_RTS) raise_rts(port); if (set & TIOCM_DTR) @@ -1271,6 +1269,7 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file, drop_rts(port); if (clear & TIOCM_DTR) drop_dtr(port); + spin_unlock_irqrestore(&port->card->card_lock, flags); return 0; } @@ -1303,7 +1302,10 @@ static int isicom_set_serial_info(struct isi_port *port, (newinfo.flags & ASYNC_FLAGS)); } if (reconfig_port) { + unsigned long flags; + spin_lock_irqsave(&port->card->card_lock, flags); isicom_config_port(port); + spin_unlock_irqrestore(&port->card->card_lock, flags); } return 0; } @@ -1384,6 +1386,7 @@ static void isicom_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct isi_port *port = tty->driver_data; + unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) return; @@ -1392,7 +1395,9 @@ static void isicom_set_termios(struct tty_struct *tty, tty->termios->c_iflag == old_termios->c_iflag) return; + spin_lock_irqsave(&port->card->card_lock, flags); isicom_config_port(port); + spin_unlock_irqrestore(&port->card->card_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1469,11 +1474,15 @@ static void do_isicom_hangup(struct work_struct *work) static void isicom_hangup(struct tty_struct *tty) { struct isi_port *port = tty->driver_data; + unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) return; + spin_lock_irqsave(&port->card->card_lock, flags); isicom_shutdown_port(port); + spin_unlock_irqrestore(&port->card->card_lock, flags); + port->count = 0; port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = NULL; @@ -1578,16 +1587,6 @@ end: return retval; } -static inline int WaitTillCardIsFree(u16 base) -{ - unsigned long count = 0; - - while (!(inw(base + 0xe) & 0x1) && count++ < 100) - msleep(5); - - return !(inw(base + 0xe) & 0x1); -} - static int __devinit load_firmware(struct pci_dev *pdev, const unsigned int index, const unsigned int signature) { diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 4f1813e0475..f5c160caf9f 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -293,8 +293,8 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; - /* Turn a pfn offset into an absolute pfn */ - pfn = PFN_DOWN(virt_to_phys((void *)PAGE_OFFSET)) + vma->vm_pgoff; + /* Turn a kernel-virtual address into a physical page frame */ + pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; /* * RED-PEN: on some architectures there is more mapped memory diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index c063359baf7..83f604b1929 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -717,6 +717,7 @@ static int mxser_init(void) /* Initialize the tty_driver structure */ memset(mxvar_sdriver, 0, sizeof(struct tty_driver)); + mxvar_sdriver->owner = THIS_MODULE; mxvar_sdriver->magic = TTY_DRIVER_MAGIC; mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->major = ttymajor; diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index cd989dce7c5..1bb030b3a51 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -2690,6 +2690,7 @@ static int __init mxser_module_init(void) MXSER_VERSION); /* Initialize the tty_driver structure */ + mxvar_sdriver->owner = THIS_MODULE; mxvar_sdriver->magic = TTY_DRIVER_MAGIC; mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->major = ttymajor; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index e1d70e8b626..664f36c98e6 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -113,7 +113,12 @@ static int rtc_has_irq = 1; #define hpet_set_rtc_irq_bit(arg) 0 #define hpet_rtc_timer_init() do { } while (0) #define hpet_rtc_dropped_irq() 0 -static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) {return 0;} +#ifdef RTC_IRQ +static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) +{ + return 0; +} +#endif #else extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); #endif diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 13935235e06..7fd3cd5ddf2 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -215,7 +215,7 @@ static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) } static struct sysrq_key_op sysrq_showstate_blocked_op = { .handler = sysrq_handle_showstate_blocked, - .help_msg = "showBlockedTasks", + .help_msg = "shoW-blocked-tasks", .action_msg = "Show Blocked State", .enable_mask = SYSRQ_ENABLE_DUMP, }; @@ -315,15 +315,16 @@ static struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_loglevel_op, /* 9 */ /* - * Don't use for system provided sysrqs, it is handled specially on - * sparc and will never arrive + * a: Don't use for system provided sysrqs, it is handled specially on + * sparc and will never arrive. */ NULL, /* a */ &sysrq_reboot_op, /* b */ - &sysrq_crashdump_op, /* c */ + &sysrq_crashdump_op, /* c & ibm_emac driver debug */ &sysrq_showlocks_op, /* d */ &sysrq_term_op, /* e */ &sysrq_moom_op, /* f */ + /* g: May be registered by ppc for kgdb */ NULL, /* g */ NULL, /* h */ &sysrq_kill_op, /* i */ @@ -332,18 +333,19 @@ static struct sysrq_key_op *sysrq_key_table[36] = { NULL, /* l */ &sysrq_showmem_op, /* m */ &sysrq_unrt_op, /* n */ - /* This will often be registered as 'Off' at init time */ + /* o: This will often be registered as 'Off' at init time */ NULL, /* o */ &sysrq_showregs_op, /* p */ NULL, /* q */ - &sysrq_unraw_op, /* r */ + &sysrq_unraw_op, /* r */ &sysrq_sync_op, /* s */ &sysrq_showstate_op, /* t */ &sysrq_mountro_op, /* u */ - /* May be assigned at init time by SMP VOYAGER */ + /* v: May be registered at init time by SMP VOYAGER */ NULL, /* v */ - NULL, /* w */ - &sysrq_showstate_blocked_op, /* x */ + &sysrq_showstate_blocked_op, /* w */ + /* x: May be registered on ppc/powerpc for xmon */ + NULL, /* x */ NULL, /* y */ NULL /* z */ }; diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 244d30a03fe..4fac2bdf621 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -186,6 +186,7 @@ static int got_event; /* if events processing have been done */ static void switchover_timeout(unsigned long data); static struct timer_list switchover_timer = TIMER_INITIALIZER(switchover_timeout , 0, 0); +static unsigned long tlclk_timer_data; static struct tlclk_alarms *alarm_events; @@ -197,10 +198,19 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id); static DECLARE_WAIT_QUEUE_HEAD(wq); +static unsigned long useflags; +static DEFINE_MUTEX(tlclk_mutex); + static int tlclk_open(struct inode *inode, struct file *filp) { int result; + if (test_and_set_bit(0, &useflags)) + return -EBUSY; + /* this legacy device is always one per system and it doesn't + * know how to handle multiple concurrent clients. + */ + /* Make sure there is no interrupt pending while * initialising interrupt handler */ inb(TLCLK_REG6); @@ -221,6 +231,7 @@ static int tlclk_open(struct inode *inode, struct file *filp) static int tlclk_release(struct inode *inode, struct file *filp) { free_irq(telclk_interrupt, tlclk_interrupt); + clear_bit(0, &useflags); return 0; } @@ -230,26 +241,25 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, { if (count < sizeof(struct tlclk_alarms)) return -EIO; + if (mutex_lock_interruptible(&tlclk_mutex)) + return -EINTR; + wait_event_interruptible(wq, got_event); - if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) + if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) { + mutex_unlock(&tlclk_mutex); return -EFAULT; + } memset(alarm_events, 0, sizeof(struct tlclk_alarms)); got_event = 0; + mutex_unlock(&tlclk_mutex); return sizeof(struct tlclk_alarms); } -static ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count, - loff_t *f_pos) -{ - return 0; -} - static const struct file_operations tlclk_fops = { .read = tlclk_read, - .write = tlclk_write, .open = tlclk_open, .release = tlclk_release, @@ -540,7 +550,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d, SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7); switch (val) { case CLK_8_592MHz: - SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); + SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); break; case CLK_11_184MHz: SET_PORT_BITS(TLCLK_REG0, 0xfc, 0); @@ -549,7 +559,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d, SET_PORT_BITS(TLCLK_REG0, 0xfc, 3); break; case CLK_44_736MHz: - SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); + SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); break; } } else @@ -807,8 +817,6 @@ static int __init tlclk_init(void) &tlclk_attribute_group); if (ret) { printk(KERN_ERR "tlclk: failed to create sysfs device attributes.\n"); - sysfs_remove_group(&tlclk_device->dev.kobj, - &tlclk_attribute_group); goto out5; } @@ -841,11 +849,13 @@ static void __exit tlclk_cleanup(void) static void switchover_timeout(unsigned long data) { - if ((data & 1)) { - if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08)) + unsigned long flags = *(unsigned long *) data; + + if ((flags & 1)) { + if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08)) alarm_events->switchover_primary++; } else { - if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08)) + if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08)) alarm_events->switchover_secondary++; } @@ -903,8 +913,9 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id) /* TIMEOUT in ~10ms */ switchover_timer.expires = jiffies + msecs_to_jiffies(10); - switchover_timer.data = inb(TLCLK_REG1); - add_timer(&switchover_timer); + tlclk_timer_data = inb(TLCLK_REG1); + switchover_timer.data = (unsigned long) &tlclk_timer_data; + mod_timer(&switchover_timer, switchover_timer.expires); } else { got_event = 1; wake_up(&wq); diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index 0e0da443cbd..8de6b95aeb8 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -42,6 +42,7 @@ #include <linux/tty_flip.h> #include <linux/sysrq.h> +#include <asm/firmware.h> #include <asm/iseries/vio.h> #include <asm/iseries/hv_lp_event.h> #include <asm/iseries/hv_call_event.h> @@ -1060,6 +1061,9 @@ static int __init viocons_init2(void) atomic_t wait_flag; int rc; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + /* +2 for fudge */ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), viomajorsubtype_chario, VIOCHAR_WINDOW + 2); @@ -1145,6 +1149,9 @@ static int __init viocons_init(void) { int i; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + printk(VIOCONS_KERN_INFO "registering console\n"); for (i = 0; i < VTTY_PORTS; i++) { port_info[i].lp = HvLpIndexInvalid; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 94d79cb8ce8..9438512b17f 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -49,7 +49,7 @@ #include <asm/uaccess.h> #include <asm/ioctls.h> - +#include <asm/firmware.h> #include <asm/vio.h> #include <asm/iseries/vio.h> #include <asm/iseries/hv_lp_event.h> @@ -997,6 +997,9 @@ int __init viotap_init(void) int ret; struct proc_dir_entry *e; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + op_struct_list = NULL; if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) { printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n"); diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index a744dad9cf4..0cea8d4907d 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -3,7 +3,7 @@ * * Copyright (C) 2002 MontaVista Software Inc. * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> - * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> * * 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 @@ -125,30 +125,17 @@ static inline uint16_t giu_clear(uint16_t offset, uint16_t clear) return data; } -static unsigned int startup_giuint_low_irq(unsigned int irq) +static void ack_giuint_low(unsigned int irq) { - unsigned int pin; - - pin = GPIO_PIN_OF_IRQ(irq); - giu_write(GIUINTSTATL, 1 << pin); - giu_set(GIUINTENL, 1 << pin); - - return 0; + giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq)); } -static void shutdown_giuint_low_irq(unsigned int irq) +static void mask_giuint_low(unsigned int irq) { giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); } -static void enable_giuint_low_irq(unsigned int irq) -{ - giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); -} - -#define disable_giuint_low_irq shutdown_giuint_low_irq - -static void ack_giuint_low_irq(unsigned int irq) +static void mask_ack_giuint_low(unsigned int irq) { unsigned int pin; @@ -157,46 +144,30 @@ static void ack_giuint_low_irq(unsigned int irq) giu_write(GIUINTSTATL, 1 << pin); } -static void end_giuint_low_irq(unsigned int irq) +static void unmask_giuint_low(unsigned int irq) { - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); } -static struct hw_interrupt_type giuint_low_irq_type = { - .typename = "GIUINTL", - .startup = startup_giuint_low_irq, - .shutdown = shutdown_giuint_low_irq, - .enable = enable_giuint_low_irq, - .disable = disable_giuint_low_irq, - .ack = ack_giuint_low_irq, - .end = end_giuint_low_irq, +static struct irq_chip giuint_low_irq_chip = { + .name = "GIUINTL", + .ack = ack_giuint_low, + .mask = mask_giuint_low, + .mask_ack = mask_ack_giuint_low, + .unmask = unmask_giuint_low, }; -static unsigned int startup_giuint_high_irq(unsigned int irq) +static void ack_giuint_high(unsigned int irq) { - unsigned int pin; - - pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; - giu_write(GIUINTSTATH, 1 << pin); - giu_set(GIUINTENH, 1 << pin); - - return 0; + giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); } -static void shutdown_giuint_high_irq(unsigned int irq) +static void mask_giuint_high(unsigned int irq) { giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); } -static void enable_giuint_high_irq(unsigned int irq) -{ - giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); -} - -#define disable_giuint_high_irq shutdown_giuint_high_irq - -static void ack_giuint_high_irq(unsigned int irq) +static void mask_ack_giuint_high(unsigned int irq) { unsigned int pin; @@ -205,20 +176,17 @@ static void ack_giuint_high_irq(unsigned int irq) giu_write(GIUINTSTATH, 1 << pin); } -static void end_giuint_high_irq(unsigned int irq) +static void unmask_giuint_high(unsigned int irq) { - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); } -static struct hw_interrupt_type giuint_high_irq_type = { - .typename = "GIUINTH", - .startup = startup_giuint_high_irq, - .shutdown = shutdown_giuint_high_irq, - .enable = enable_giuint_high_irq, - .disable = disable_giuint_high_irq, - .ack = ack_giuint_high_irq, - .end = end_giuint_high_irq, +static struct irq_chip giuint_high_irq_chip = { + .name = "GIUINTH", + .ack = ack_giuint_high, + .mask = mask_giuint_high, + .mask_ack = mask_ack_giuint_high, + .unmask = unmask_giuint_high, }; static int giu_get_irq(unsigned int irq) @@ -282,9 +250,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_ break; } } + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_low_irq_chip, + handle_edge_irq); } else { giu_clear(GIUINTTYPL, mask); giu_clear(GIUINTHTSELL, mask); + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_low_irq_chip, + handle_level_irq); } giu_write(GIUINTSTATL, mask); } else if (pin < GIUINT_HIGH_MAX) { @@ -311,9 +285,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_ break; } } + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_high_irq_chip, + handle_edge_irq); } else { giu_clear(GIUINTTYPH, mask); giu_clear(GIUINTHTSELH, mask); + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_high_irq_chip, + handle_level_irq); } giu_write(GIUINTSTATH, mask); } @@ -617,10 +597,11 @@ static const struct file_operations gpio_fops = { static int __devinit giu_probe(struct platform_device *dev) { unsigned long start, size, flags = 0; - unsigned int nr_pins = 0; + unsigned int nr_pins = 0, trigger, i, pin; struct resource *res1, *res2 = NULL; void *base; - int retval, i; + struct irq_chip *chip; + int retval; switch (current_cpu_data.cputype) { case CPU_VR4111: @@ -688,11 +669,20 @@ static int __devinit giu_probe(struct platform_device *dev) giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); + trigger = giu_read(GIUINTTYPH) << 16; + trigger |= giu_read(GIUINTTYPL); for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { - if (i < GIU_IRQ(GIUINT_HIGH_OFFSET)) - irq_desc[i].chip = &giuint_low_irq_type; + pin = GPIO_PIN_OF_IRQ(i); + if (pin < GIUINT_HIGH_OFFSET) + chip = &giuint_low_irq_chip; else - irq_desc[i].chip = &giuint_high_irq_type; + chip = &giuint_high_irq_chip; + + if (trigger & (1 << pin)) + set_irq_chip_and_handler(i, chip, handle_edge_irq); + else + set_irq_chip_and_handler(i, chip, handle_level_irq); + } return cascade_irq(GIUINT_IRQ, giu_get_irq); diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 3ece6923134..5c9f67f98d1 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -28,6 +28,7 @@ #include <linux/init.h> #include <linux/connector.h> #include <asm/atomic.h> +#include <asm/unaligned.h> #include <linux/cn_proc.h> @@ -60,7 +61,7 @@ void proc_fork_connector(struct task_struct *task) ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_FORK; ev->event_data.fork.parent_pid = task->real_parent->pid; ev->event_data.fork.parent_tgid = task->real_parent->tgid; @@ -88,7 +89,7 @@ void proc_exec_connector(struct task_struct *task) ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_EXEC; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid; @@ -124,7 +125,7 @@ void proc_id_connector(struct task_struct *task, int which_id) return; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -146,7 +147,7 @@ void proc_exit_connector(struct task_struct *task) ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_EXIT; ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_tgid = task->tgid; @@ -181,7 +182,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) ev = (struct proc_event*)msg->data; msg->seq = rcvd_seq; ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->cpu = -1; ev->what = PROC_EVENT_NONE; ev->event_data.ack.err = err; diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index b418b16e910..296f51002b5 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -34,7 +34,7 @@ void cn_queue_wrapper(struct work_struct *work) { struct cn_callback_entry *cbq = - container_of(work, struct cn_callback_entry, work.work); + container_of(work, struct cn_callback_entry, work); struct cn_callback_data *d = &cbq->data; d->callback(d->callback_priv); @@ -59,13 +59,12 @@ static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struc memcpy(&cbq->id.id, id, sizeof(struct cb_id)); cbq->data.callback = callback; - INIT_DELAYED_WORK(&cbq->work, &cn_queue_wrapper); + INIT_WORK(&cbq->work, &cn_queue_wrapper); return cbq; } static void cn_queue_free_callback(struct cn_callback_entry *cbq) { - cancel_delayed_work(&cbq->work); flush_workqueue(cbq->pdev->cn_queue); kfree(cbq); diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 5e7cd45d10e..a44db75bc25 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -135,17 +135,15 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v spin_lock_bh(&dev->cbdev->queue_lock); list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { if (cn_cb_equal(&__cbq->id.id, &msg->id)) { - if (likely(!test_bit(WORK_STRUCT_PENDING, - &__cbq->work.work.management) && + if (likely(!work_pending(&__cbq->work) && __cbq->data.ddata == NULL)) { __cbq->data.callback_priv = msg; __cbq->data.ddata = data; __cbq->data.destruct_data = destruct_data; - if (queue_delayed_work( - dev->cbdev->cn_queue, - &__cbq->work, 0)) + if (queue_work(dev->cbdev->cn_queue, + &__cbq->work)) err = 0; } else { struct cn_callback_data *d; @@ -159,12 +157,11 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v d->destruct_data = destruct_data; d->free = __cbq; - INIT_DELAYED_WORK(&__cbq->work, - &cn_queue_wrapper); + INIT_WORK(&__cbq->work, + &cn_queue_wrapper); - if (queue_delayed_work( - dev->cbdev->cn_queue, - &__cbq->work, 0)) + if (queue_work(dev->cbdev->cn_queue, + &__cbq->work)) err = 0; else { kfree(__cbq); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d91330432ba..a45cc89e387 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -722,8 +722,13 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) spin_unlock_irqrestore(&cpufreq_driver_lock, flags); dprintk("CPU already managed, adding link\n"); - sysfs_create_link(&sys_dev->kobj, - &managed_policy->kobj, "cpufreq"); + ret = sysfs_create_link(&sys_dev->kobj, + &managed_policy->kobj, + "cpufreq"); + if (ret) { + mutex_unlock(&policy->lock); + goto err_out_driver_exit; + } cpufreq_debug_enable_ratelimit(); mutex_unlock(&policy->lock); @@ -770,8 +775,12 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) dprintk("CPU %u already managed, adding link\n", j); cpufreq_cpu_get(cpu); cpu_sys_dev = get_cpu_sysdev(j); - sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, - "cpufreq"); + ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, + "cpufreq"); + if (ret) { + mutex_unlock(&policy->lock); + goto err_out_unregister; + } } policy->governor = NULL; /* to assure that the starting sequence is diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 6742b1adf2c..91ad342a605 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -285,6 +285,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, stat = cpufreq_stats_table[freq->cpu]; if (!stat) return 0; + old_index = freq_table_get_index(stat, freq->old); new_index = freq_table_get_index(stat, freq->new); @@ -292,6 +293,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, if (old_index == new_index) return 0; + if (old_index == -1 || new_index == -1) + return 0; + spin_lock(&cpufreq_stats_lock); stat->last_index = new_index; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 5ab5e393b88..c6281ccd4fe 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -122,8 +122,6 @@ struct efivar_entry { struct kobject kobj; }; -#define get_efivar_entry(n) list_entry(n, struct efivar_entry, list) - struct efivar_attribute { struct attribute attr; ssize_t (*show) (struct efivar_entry *entry, char *buf); @@ -386,9 +384,6 @@ static struct sysfs_ops efivar_attr_ops = { static void efivar_release(struct kobject *kobj) { struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj); - spin_lock(&efivars_lock); - list_del(&var->list); - spin_unlock(&efivars_lock); kfree(var); } @@ -430,9 +425,8 @@ static ssize_t efivar_create(struct subsystem *sub, const char *buf, size_t count) { struct efi_variable *new_var = (struct efi_variable *)buf; - struct efivar_entry *search_efivar = NULL; + struct efivar_entry *search_efivar, *n; unsigned long strsize1, strsize2; - struct list_head *pos, *n; efi_status_t status = EFI_NOT_FOUND; int found = 0; @@ -444,8 +438,7 @@ efivar_create(struct subsystem *sub, const char *buf, size_t count) /* * Does this variable already exist? */ - list_for_each_safe(pos, n, &efivar_list) { - search_efivar = get_efivar_entry(pos); + list_for_each_entry_safe(search_efivar, n, &efivar_list, list) { strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); strsize2 = utf8_strsize(new_var->VariableName, 1024); if (strsize1 == strsize2 && @@ -490,9 +483,8 @@ static ssize_t efivar_delete(struct subsystem *sub, const char *buf, size_t count) { struct efi_variable *del_var = (struct efi_variable *)buf; - struct efivar_entry *search_efivar = NULL; + struct efivar_entry *search_efivar, *n; unsigned long strsize1, strsize2; - struct list_head *pos, *n; efi_status_t status = EFI_NOT_FOUND; int found = 0; @@ -504,8 +496,7 @@ efivar_delete(struct subsystem *sub, const char *buf, size_t count) /* * Does this variable already exist? */ - list_for_each_safe(pos, n, &efivar_list) { - search_efivar = get_efivar_entry(pos); + list_for_each_entry_safe(search_efivar, n, &efivar_list, list) { strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); strsize2 = utf8_strsize(del_var->VariableName, 1024); if (strsize1 == strsize2 && @@ -537,9 +528,9 @@ efivar_delete(struct subsystem *sub, const char *buf, size_t count) spin_unlock(&efivars_lock); return -EIO; } + list_del(&search_efivar->list); /* We need to release this lock before unregistering. */ spin_unlock(&efivars_lock); - efivar_unregister(search_efivar); /* It's dead Jim.... */ @@ -768,10 +759,14 @@ out_free: static void __exit efivars_exit(void) { - struct list_head *pos, *n; + struct efivar_entry *entry, *n; - list_for_each_safe(pos, n, &efivar_list) - efivar_unregister(get_efivar_entry(pos)); + list_for_each_entry_safe(entry, n, &efivar_list, list) { + spin_lock(&efivars_lock); + list_del(&entry->list); + spin_unlock(&efivars_lock); + efivar_unregister(entry); + } subsystem_unregister(&vars_subsys); firmware_unregister(&efi_subsys); diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 96d4a0bb220..ec796ad087d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -6,13 +6,21 @@ menu "HID Devices" config HID tristate "Generic HID support" + depends on INPUT default y ---help--- - Say Y here if you want generic HID support to connect keyboards, - mice, joysticks, graphic tablets, or any other HID based devices - to your computer. You also need to select particular types of - HID devices you want to compile support for, in the particular - driver menu (USB, Bluetooth) + A human interface device (HID) is a type of computer device that + interacts directly with and takes input from humans. The term "HID" + most commonly used to refer to the USB-HID specification, but other + devices (such as, but not strictly limited to, Bluetooth) are + designed using HID specification (this involves certain keyboards, + mice, tablets, etc). This option compiles into kernel the generic + HID layer code (parser, usages, etc.), which can then be used by + transport-specific HID implementation (like USB or Bluetooth). + + For docs and specs, see http://www.usb.org/developers/hidpage/ + + If unsure, say Y endmenu diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 18c2b3cf6bc..49f18f5b251 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -40,18 +40,10 @@ #define DRIVER_VERSION "v2.6" #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" -#define DRIVER_DESC "USB HID core driver" +#define DRIVER_DESC "HID core driver" #define DRIVER_LICENSE "GPL" /* - * Module parameters. - */ - -static unsigned int hid_mousepoll_interval; -module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); -MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); - -/* * Register a new report for a device. */ @@ -551,6 +543,7 @@ void hid_free_device(struct hid_device *device) } kfree(device->rdesc); + kfree(device->collection); kfree(device); } EXPORT_SYMBOL_GPL(hid_free_device); @@ -656,7 +649,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) for (i = 0; i < HID_REPORT_TYPES; i++) INIT_LIST_HEAD(&device->report_enum[i].report_list); - if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { + if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) { kfree(device->collection); kfree(device); return NULL; @@ -888,6 +881,10 @@ static void hid_output_field(struct hid_field *field, __u8 *data) unsigned size = field->report_size; unsigned n; + /* make sure the unused bits in the last byte are zeros */ + if (count > 0 && size > 0) + data[(count*size-1)/8] = 0; + for (n = 0; n < count; n++) { if (field->logical_minimum < 0) /* signed values */ implement(data, offset + n * size, size, s32ton(field->value[n], size)); @@ -955,7 +952,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i } #ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); + printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); #endif n = 0; /* Normally report number is 0 */ diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 14cdf09316c..c7a6833f682 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -30,12 +30,16 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/kernel.h> -#include <linux/usb/input.h> #undef DEBUG #include <linux/hid.h> +static int hid_pb_fnmode = 1; +module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644); +MODULE_PARM_DESC(pb_fnmode, + "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); + #define unk KEY_UNKNOWN static const unsigned char hid_keyboard[256] = { @@ -68,6 +72,7 @@ static const struct { #define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) +#define map_rel_clear(c) do { map_rel(c); clear_bit(c, bit); } while (0) #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) #ifdef CONFIG_USB_HIDINPUT_POWERBOOK @@ -154,7 +159,7 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, return 1; } - if (hid->pb_fnmode) { + if (hid_pb_fnmode) { int do_translate; trans = find_translation(powerbook_fn_keys, usage->code); @@ -163,8 +168,8 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, do_translate = 1; else if (trans->flags & POWERBOOK_FLAG_FKEY) do_translate = - (hid->pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (hid->pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); + (hid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || + (hid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); else do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); @@ -292,7 +297,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } } - map_key(code); + map_key_clear(code); break; @@ -343,9 +348,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel(usage->hid & 0xf); + map_rel_clear(usage->hid & 0xf); else - map_abs(usage->hid & 0xf); + map_abs_clear(usage->hid & 0xf); break; case HID_GD_HATSWITCH: @@ -363,9 +368,22 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; case HID_UP_LED: - if (((usage->hid - 1) & 0xffff) >= LED_MAX) - goto ignore; - map_led((usage->hid - 1) & 0xffff); + + switch (usage->hid & 0xffff) { /* HID-Value: */ + case 0x01: map_led (LED_NUML); break; /* "Num Lock" */ + case 0x02: map_led (LED_CAPSL); break; /* "Caps Lock" */ + case 0x03: map_led (LED_SCROLLL); break; /* "Scroll Lock" */ + case 0x04: map_led (LED_COMPOSE); break; /* "Compose" */ + case 0x05: map_led (LED_KANA); break; /* "Kana" */ + case 0x27: map_led (LED_SLEEP); break; /* "Stand-By" */ + case 0x4c: map_led (LED_SUSPEND); break; /* "System Suspend" */ + case 0x09: map_led (LED_MUTE); break; /* "Mute" */ + case 0x4b: map_led (LED_MISC); break; /* "Generic Indicator" */ + case 0x19: map_led (LED_MAIL); break; /* "Message Waiting" */ + case 0x4d: map_led (LED_CHARGING); break; /* "External Power Connected" */ + + default: goto ignore; + } break; case HID_UP_DIGITIZER: @@ -415,12 +433,33 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x000: goto ignore; case 0x034: map_key_clear(KEY_SLEEP); break; case 0x036: map_key_clear(BTN_MISC); break; + case 0x040: map_key_clear(KEY_MENU); break; case 0x045: map_key_clear(KEY_RADIO); break; + + case 0x083: map_key_clear(KEY_LAST); break; + case 0x088: map_key_clear(KEY_PC); break; + case 0x089: map_key_clear(KEY_TV); break; case 0x08a: map_key_clear(KEY_WWW); break; + case 0x08b: map_key_clear(KEY_DVD); break; + case 0x08c: map_key_clear(KEY_PHONE); break; case 0x08d: map_key_clear(KEY_PROGRAM); break; + case 0x08e: map_key_clear(KEY_VIDEOPHONE); break; + case 0x08f: map_key_clear(KEY_GAMES); break; + case 0x090: map_key_clear(KEY_MEMO); break; + case 0x091: map_key_clear(KEY_CD); break; + case 0x092: map_key_clear(KEY_VCR); break; + case 0x093: map_key_clear(KEY_TUNER); break; + case 0x094: map_key_clear(KEY_EXIT); break; case 0x095: map_key_clear(KEY_HELP); break; + case 0x096: map_key_clear(KEY_TAPE); break; + case 0x097: map_key_clear(KEY_TV2); break; + case 0x098: map_key_clear(KEY_SAT); break; + case 0x09a: map_key_clear(KEY_PVR); break; + case 0x09c: map_key_clear(KEY_CHANNELUP); break; case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; + case 0x0a0: map_key_clear(KEY_VCR2); break; + case 0x0b0: map_key_clear(KEY_PLAY); break; case 0x0b1: map_key_clear(KEY_PAUSE); break; case 0x0b2: map_key_clear(KEY_RECORD); break; @@ -430,6 +469,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break; case 0x0b7: map_key_clear(KEY_STOPCD); break; case 0x0b8: map_key_clear(KEY_EJECTCD); break; + case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; case 0x0e0: map_abs_clear(ABS_VOLUME); break; case 0x0e2: map_key_clear(KEY_MUTE); break; @@ -437,11 +477,30 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; case 0x183: map_key_clear(KEY_CONFIG); break; + case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; + case 0x185: map_key_clear(KEY_EDITOR); break; + case 0x186: map_key_clear(KEY_SPREADSHEET); break; + case 0x187: map_key_clear(KEY_GRAPHICSEDITOR); break; + case 0x188: map_key_clear(KEY_PRESENTATION); break; + case 0x189: map_key_clear(KEY_DATABASE); break; case 0x18a: map_key_clear(KEY_MAIL); break; + case 0x18b: map_key_clear(KEY_NEWS); break; + case 0x18c: map_key_clear(KEY_VOICEMAIL); break; + case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break; + case 0x18e: map_key_clear(KEY_CALENDAR); break; + case 0x191: map_key_clear(KEY_FINANCE); break; case 0x192: map_key_clear(KEY_CALC); break; case 0x194: map_key_clear(KEY_FILE); break; + case 0x196: map_key_clear(KEY_WWW); break; + case 0x19e: map_key_clear(KEY_COFFEE); break; + case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; + case 0x1bc: map_key_clear(KEY_MESSENGER); break; + case 0x1bd: map_key_clear(KEY_INFO); break; case 0x201: map_key_clear(KEY_NEW); break; + case 0x202: map_key_clear(KEY_OPEN); break; + case 0x203: map_key_clear(KEY_CLOSE); break; + case 0x204: map_key_clear(KEY_EXIT); break; case 0x207: map_key_clear(KEY_SAVE); break; case 0x208: map_key_clear(KEY_PRINT); break; case 0x209: map_key_clear(KEY_PROPS); break; @@ -456,10 +515,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x226: map_key_clear(KEY_STOP); break; case 0x227: map_key_clear(KEY_REFRESH); break; case 0x22a: map_key_clear(KEY_BOOKMARKS); break; + case 0x22d: map_key_clear(KEY_ZOOMIN); break; + case 0x22e: map_key_clear(KEY_ZOOMOUT); break; + case 0x22f: map_key_clear(KEY_ZOOMRESET); break; case 0x233: map_key_clear(KEY_SCROLLUP); break; case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel(REL_HWHEEL); break; + case 0x238: map_rel_clear(REL_HWHEEL); break; + case 0x25f: map_key_clear(KEY_CANCEL); break; case 0x279: map_key_clear(KEY_REDO); break; + case 0x289: map_key_clear(KEY_REPLY); break; case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; case 0x28c: map_key_clear(KEY_SEND); break; diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 31c42002708..b80f6ed5acf 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -93,7 +93,7 @@ int vid_from_reg(int val, u8 vrm) case 110: /* Intel Conroe */ /* compute in uV, round to mV */ val &= 0xff; - if(((val & 0x7e) == 0xfe) || (!(val & 0x7e))) + if (val < 0x02 || val > 0xb2) return 0; return((1600000 - (val - 2) * 6250 + 500) / 1000); case 24: /* Opteron processor */ diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index c12ac5abc2b..253ffaf1568 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -117,6 +117,7 @@ static const u16 W83793_REG_IN[][3] = { /* Low Bits of Vcore A/B Vtt Read/High/Low */ static const u16 W83793_REG_IN_LOW_BITS[] = { 0x1b, 0x68, 0x69 }; static u8 scale_in[] = { 2, 2, 2, 16, 16, 16, 8, 24, 24, 16 }; +static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 }; #define W83793_REG_FAN(index) (0x23 + 2 * (index)) /* High byte */ #define W83793_REG_FAN_MIN(index) (0x90 + 2 * (index)) /* High byte */ @@ -203,6 +204,8 @@ struct w83793_data { u8 temp_fan_map[6]; /* Temp controls which pwm fan, bit field */ u8 has_pwm; + u8 has_temp; + u8 has_vid; u8 pwm_enable; /* Register value, each Temp has 1 bit */ u8 pwm_uptime; /* Register value */ u8 pwm_downtime; /* Register value */ @@ -500,7 +503,7 @@ store_temp(struct device *dev, struct device_attribute *attr, each has 4 mode:(2 bits) 0: Stop monitor 1: Use internal temp sensor(default) - 2: Use sensor in AMD CPU and get result by AMDSI + 2: Reserved 3: Use sensor in Intel CPU and get result by PECI TR1-TR2 @@ -509,8 +512,8 @@ store_temp(struct device *dev, struct device_attribute *attr, 1: To enable temp sensors monitor */ -/* 0 disable, 5 AMDSI, 6 PECI */ -static u8 TO_TEMP_MODE[] = { 0, 0, 5, 6 }; +/* 0 disable, 6 PECI */ +static u8 TO_TEMP_MODE[] = { 0, 0, 0, 6 }; static ssize_t show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) @@ -550,11 +553,10 @@ store_temp_mode(struct device *dev, struct device_attribute *attr, u8 val = simple_strtoul(buf, NULL, 10); /* transform the sysfs interface values into table above */ - if ((val == 5 || val == 6) && (index < 4)) { + if ((val == 6) && (index < 4)) { val -= 3; } else if ((val == 3 && index < 4) - || (val == 4 && index >= 4) - || val == 0) { + || (val == 4 && index >= 4)) { /* transform diode or thermistor into internal enable */ val = !!val; } else { @@ -839,7 +841,9 @@ show_in(struct device *dev, struct device_attribute *attr, char *buf) val <<= 2; val += (data->in_low_bits[nr] >> (index * 2)) & 0x3; } - return sprintf(buf, "%d\n", val * scale_in[index]); + /* voltage inputs 5VDD and 5VSB needs 150mV offset */ + val = val * scale_in[index] + scale_in_add[index]; + return sprintf(buf, "%d\n", val); } static ssize_t @@ -859,6 +863,10 @@ store_in(struct device *dev, struct device_attribute *attr, scale_in[index] / 2) / scale_in[index]; mutex_lock(&data->update_lock); if (index > 2) { + /* fix the limit values of 5VDD and 5VSB to ALARM mechanism */ + if (1 == nr || 2 == nr) { + val -= scale_in_add[index] / scale_in[index]; + } val = SENSORS_LIMIT(val, 0, 255); } else { val = SENSORS_LIMIT(val, 0, 0x3FF); @@ -979,12 +987,6 @@ static struct sensor_device_attribute_2 w83793_sensor_attr_2[] = { SENSOR_ATTR_IN(7), SENSOR_ATTR_IN(8), SENSOR_ATTR_IN(9), - SENSOR_ATTR_TEMP(1), - SENSOR_ATTR_TEMP(2), - SENSOR_ATTR_TEMP(3), - SENSOR_ATTR_TEMP(4), - SENSOR_ATTR_TEMP(5), - SENSOR_ATTR_TEMP(6), SENSOR_ATTR_FAN(1), SENSOR_ATTR_FAN(2), SENSOR_ATTR_FAN(3), @@ -995,6 +997,15 @@ static struct sensor_device_attribute_2 w83793_sensor_attr_2[] = { SENSOR_ATTR_PWM(3), }; +static struct sensor_device_attribute_2 w83793_temp[] = { + SENSOR_ATTR_TEMP(1), + SENSOR_ATTR_TEMP(2), + SENSOR_ATTR_TEMP(3), + SENSOR_ATTR_TEMP(4), + SENSOR_ATTR_TEMP(5), + SENSOR_ATTR_TEMP(6), +}; + /* Fan6-Fan12 */ static struct sensor_device_attribute_2 w83793_left_fan[] = { SENSOR_ATTR_FAN(6), @@ -1015,9 +1026,12 @@ static struct sensor_device_attribute_2 w83793_left_pwm[] = { SENSOR_ATTR_PWM(8), }; -static struct sensor_device_attribute_2 sda_single_files[] = { +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 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, @@ -1070,11 +1084,17 @@ static int w83793_detach_client(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) device_remove_file(dev, &sda_single_files[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) + device_remove_file(dev, &w83793_vid[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++) device_remove_file(dev, &w83793_left_fan[i].dev_attr); for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++) device_remove_file(dev, &w83793_left_pwm[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) + device_remove_file(dev, &w83793_temp[i].dev_attr); } if ((err = i2c_detach_client(client))) @@ -1187,6 +1207,7 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) struct w83793_data *data; int files_fan = ARRAY_SIZE(w83793_left_fan) / 7; int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5; + int files_temp = ARRAY_SIZE(w83793_temp) / 6; int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -1313,6 +1334,44 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) data->has_pwm |= 0x80; } + tmp = w83793_read_value(client, W83793_REG_FANIN_SEL); + if ((tmp & 0x01) && (val & 0x08)) { /* fan 9, second location */ + data->has_fan |= 0x100; + } + if ((tmp & 0x02) && (val & 0x10)) { /* fan 10, second location */ + data->has_fan |= 0x200; + } + if ((tmp & 0x04) && (val & 0x20)) { /* fan 11, second location */ + data->has_fan |= 0x400; + } + if ((tmp & 0x08) && (val & 0x40)) { /* fan 12, second location */ + data->has_fan |= 0x800; + } + + /* check the temp1-6 mode, ignore former AMDSI selected inputs */ + tmp = w83793_read_value(client,W83793_REG_TEMP_MODE[0]); + if (tmp & 0x01) + data->has_temp |= 0x01; + if (tmp & 0x04) + data->has_temp |= 0x02; + if (tmp & 0x10) + data->has_temp |= 0x04; + if (tmp & 0x40) + data->has_temp |= 0x08; + + tmp = w83793_read_value(client,W83793_REG_TEMP_MODE[1]); + if (tmp & 0x01) + data->has_temp |= 0x10; + 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, @@ -1321,6 +1380,14 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } + for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) { + if (!(data->has_vid & (1 << i))) + continue; + err = device_create_file(dev, &w83793_vid[i].dev_attr); + 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); if (err) @@ -1328,6 +1395,19 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) } + for (i = 0; i < 6; i++) { + int j; + if (!(data->has_temp & (1 << i))) + continue; + for (j = 0; j < files_temp; j++) { + err = device_create_file(dev, + &w83793_temp[(i) * files_temp + + j].dev_attr); + if (err) + goto exit_remove; + } + } + for (i = 5; i < 12; i++) { int j; if (!(data->has_fan & (1 << i))) @@ -1371,12 +1451,18 @@ exit_remove: for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) device_remove_file(dev, &sda_single_files[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) + device_remove_file(dev, &w83793_vid[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++) device_remove_file(dev, &w83793_left_fan[i].dev_attr); for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++) device_remove_file(dev, &w83793_left_pwm[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) + device_remove_file(dev, &w83793_temp[i].dev_attr); + if (data->lm75[0] != NULL) { i2c_detach_client(data->lm75[0]); kfree(data->lm75[0]); @@ -1428,6 +1514,8 @@ static void w83793_update_nonvolatile(struct device *dev) } for (i = 0; i < ARRAY_SIZE(data->temp_fan_map); i++) { + if (!(data->has_temp & (1 << i))) + continue; data->temp_fan_map[i] = w83793_read_value(client, W83793_REG_TEMP_FAN_MAP(i)); for (j = 1; j < 5; j++) { @@ -1510,9 +1598,12 @@ static struct w83793_data *w83793_update_device(struct device *dev) w83793_read_value(client, W83793_REG_FAN(i) + 1); } - for (i = 0; i < ARRAY_SIZE(data->temp); i++) + for (i = 0; i < ARRAY_SIZE(data->temp); i++) { + if (!(data->has_temp & (1 << i))) + continue; data->temp[i][TEMP_READ] = w83793_read_value(client, W83793_REG_TEMP[i][TEMP_READ]); + } data->temp_low_bits = w83793_read_value(client, W83793_REG_TEMP_LOW_BITS); @@ -1527,8 +1618,10 @@ static struct w83793_data *w83793_update_device(struct device *dev) for (i = 0; i < ARRAY_SIZE(data->alarms); i++) data->alarms[i] = w83793_read_value(client, W83793_REG_ALARM(i)); - data->vid[0] = w83793_read_value(client, W83793_REG_VID_INA); - data->vid[1] = w83793_read_value(client, W83793_REG_VID_INB); + if (data->has_vid & 0x01) + data->vid[0] = w83793_read_value(client, W83793_REG_VID_INA); + if (data->has_vid & 0x02) + data->vid[1] = w83793_read_value(client, W83793_REG_VID_INB); w83793_update_nonvolatile(dev); data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e1989f3a268..9367c4cfe93 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -564,13 +564,4 @@ config I2C_PNX This driver can also be built as a module. If so, the module will be called i2c-pnx. -config I2C_PNX_EARLY - bool "Early initialization for I2C on PNXxxxx" - depends on I2C_PNX=y - help - Under certain circumstances one may need to make sure I2C on PNXxxxx - is initialized earlier than some other driver that depends on it - (for instance, that might be USB in case of PNX4008). With this - option turned on you can guarantee that. - endmenu diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index bbc8e3a7ff5..490173611d6 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -529,6 +529,8 @@ mv64xxx_i2c_probe(struct platform_device *pd) platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); + mv64xxx_i2c_hw_init(drv_data); + if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, MV64XXX_I2C_CTLR_NAME, drv_data)) { dev_err(&drv_data->adapter.dev, @@ -542,8 +544,6 @@ mv64xxx_i2c_probe(struct platform_device *pd) goto exit_free_irq; } - mv64xxx_i2c_hw_init(drv_data); - return 0; exit_free_irq: diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index de0bca77e92..17376feb1ac 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -305,8 +305,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) return 0; } -static irqreturn_t -i2c_pnx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) { u32 stat, ctl; struct i2c_adapter *adap = dev_id; @@ -699,10 +698,6 @@ MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>"); MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses"); MODULE_LICENSE("GPL"); -#ifdef CONFIG_I2C_PNX_EARLY /* We need to make sure I2C is initialized before USB */ subsys_initcall(i2c_adap_pnx_init); -#else -mudule_init(i2c_adap_pnx_init); -#endif module_exit(i2c_adap_pnx_exit); diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 420377c8642..3fcb646e207 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -209,6 +209,7 @@ m41t00_set(void *arg) buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f); buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f); buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f); + buf[m41t00_chip->year] = year; if (i2c_master_send(save_client, wbuf, 9) < 0) dev_err(&save_client->dev, "m41t00_set: Write error\n"); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3e31f1d265c..b05378a3d67 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -95,16 +95,32 @@ struct device_driver i2c_adapter_driver = { .bus = &i2c_bus_type, }; +/* ------------------------------------------------------------------------- */ + +/* I2C bus adapters -- one roots each I2C or SMBUS segment */ + static void i2c_adapter_class_dev_release(struct class_device *dev) { struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev); complete(&adap->class_dev_released); } +static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf) +{ + struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev); + return sprintf(buf, "%s\n", adap->name); +} + +static struct class_device_attribute i2c_adapter_attrs[] = { + __ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL), + { }, +}; + struct class i2c_adapter_class = { - .owner = THIS_MODULE, - .name = "i2c-adapter", - .release = &i2c_adapter_class_dev_release, + .owner = THIS_MODULE, + .name = "i2c-adapter", + .class_dev_attrs = i2c_adapter_attrs, + .release = &i2c_adapter_class_dev_release, }; static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -175,8 +191,12 @@ int i2c_add_adapter(struct i2c_adapter *adap) * If the parent pointer is not set up, * we add this adapter to the host bus. */ - if (adap->dev.parent == NULL) + if (adap->dev.parent == NULL) { adap->dev.parent = &platform_bus; + printk(KERN_WARNING "**WARNING** I2C adapter driver [%s] " + "forgot to specify physical device; fix it!\n", + adap->name); + } sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); adap->dev.driver = &i2c_adapter_driver; adap->dev.release = &i2c_adapter_dev_release; diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index df7d1504f84..98410ca044c 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -73,3 +73,8 @@ void __init pnpide_init(void) { pnp_register_driver(&idepnp_driver); } + +void __exit pnpide_exit(void) +{ + pnp_unregister_driver(&idepnp_driver); +} diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 16890769dca..6c9bd5165bd 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1781,8 +1781,9 @@ done: return 1; } -extern void pnpide_init(void); -extern void h8300_ide_init(void); +extern void __init pnpide_init(void); +extern void __exit pnpide_exit(void); +extern void __init h8300_ide_init(void); /* * probe_for_hwifs() finds/initializes "known" IDE interfaces @@ -2087,13 +2088,17 @@ int __init init_module (void) return ide_init(); } -void cleanup_module (void) +void __exit cleanup_module (void) { int index; for (index = 0; index < MAX_HWIFS; ++index) ide_unregister(index); +#ifdef CONFIG_BLK_DEV_IDEPNP + pnpide_exit(); +#endif + #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index f286079d233..d261bfbad22 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -441,7 +441,7 @@ static struct pci_driver driver = { .probe = aec62xx_init_one, }; -static int aec62xx_ide_init(void) +static int __init aec62xx_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 89109be5162..68df77ec502 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -907,7 +907,7 @@ static struct pci_driver driver = { .probe = alim15x3_init_one, }; -static int ali15x3_ide_init(void) +static int __init ali15x3_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 753fe0e2145..a4336995a41 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -544,7 +544,7 @@ static struct pci_driver driver = { .probe = amd74xx_probe, }; -static int amd74xx_ide_init(void) +static int __init amd74xx_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index d55b938b1ae..982ac31fa99 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -46,6 +46,8 @@ static atiixp_ide_timing mdma_timing[] = { static int save_mdma_mode[4]; +static DEFINE_SPINLOCK(atiixp_lock); + /** * atiixp_ratemask - compute rate mask for ATIIXP IDE * @drive: IDE drive to compute for @@ -105,7 +107,7 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive) unsigned long flags; u16 tmp16; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&atiixp_lock, flags); pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); if (save_mdma_mode[drive->dn]) @@ -114,7 +116,7 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive) tmp16 |= (1 << drive->dn); pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&atiixp_lock, flags); return __ide_dma_host_on(drive); } @@ -125,13 +127,13 @@ static int atiixp_ide_dma_host_off(ide_drive_t *drive) unsigned long flags; u16 tmp16; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&atiixp_lock, flags); pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); tmp16 &= ~(1 << drive->dn); pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&atiixp_lock, flags); return __ide_dma_host_off(drive); } @@ -152,7 +154,7 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) u32 pio_timing_data; u16 pio_mode_data; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&atiixp_lock, flags); pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); pio_mode_data &= ~(0x07 << (drive->dn * 4)); @@ -165,7 +167,7 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) (pio_timing[pio].command_width << (timing_shift + 4)); pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&atiixp_lock, flags); } /** @@ -189,7 +191,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed) speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed); - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&atiixp_lock, flags); save_mdma_mode[drive->dn] = 0; if (speed >= XFER_UDMA_0) { @@ -208,7 +210,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed) } } - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&atiixp_lock, flags); if (speed >= XFER_SW_DMA_0) pio = atiixp_dma_2_pio(speed); @@ -289,8 +291,12 @@ fast_ata_pio: static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) { + u8 udma_mode = 0; + u8 ch = hwif->channel; + struct pci_dev *pdev = hwif->pci_dev; + if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; + hwif->irq = ch ? 15 : 14; hwif->autodma = 0; hwif->tuneproc = &atiixp_tuneproc; @@ -306,8 +312,12 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) hwif->mwdma_mask = 0x06; hwif->swdma_mask = 0x04; - /* FIXME: proper cable detection needed */ - hwif->udma_four = 1; + pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode); + if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40) + hwif->udma_four = 1; + else + hwif->udma_four = 0; + hwif->ide_dma_host_on = &atiixp_ide_dma_host_on; hwif->ide_dma_host_off = &atiixp_ide_dma_host_off; hwif->ide_dma_check = &atiixp_dma_check; @@ -318,19 +328,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) hwif->drives[0].autodma = hwif->autodma; } -static void __devinit init_hwif_sb600_legacy(ide_hwif_t *hwif) -{ - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} static ide_pci_device_t atiixp_pci_info[] __devinitdata = { { /* 0 */ @@ -341,12 +338,13 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = { .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, .bootable = ON_BOARD, },{ /* 1 */ - .name = "ATI SB600 SATA Legacy IDE", - .init_hwif = init_hwif_sb600_legacy, - .channels = 2, + .name = "SB600_PATA", + .init_hwif = init_hwif_atiixp, + .channels = 1, .autodma = AUTODMA, - .bootable = ON_BOARD, - } + .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}}, + .bootable = ON_BOARD, + }, }; /** @@ -367,8 +365,7 @@ static struct pci_device_id atiixp_pci_tbl[] = { { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, PCI_ANY_ID, PCI_ANY_ID, (PCI_CLASS_STORAGE_IDE<<8)|0x8a, 0xffff05, 1}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); @@ -379,7 +376,7 @@ static struct pci_driver driver = { .probe = atiixp_init_one, }; -static int atiixp_ide_init(void) +static int __init atiixp_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 20c32716bbc..aee947e8fc3 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -793,7 +793,7 @@ static struct pci_driver driver = { .probe = cmd64x_init_one, }; -static int cmd64x_ide_init(void) +static int __init cmd64x_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 079f7c86726..ba6786aabf3 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -260,7 +260,7 @@ static struct pci_driver driver = { .probe = cs5520_init_one, }; -static int cs5520_ide_init(void) +static int __init cs5520_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index ae405fa3223..9bf5fdfc5b1 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -374,7 +374,7 @@ static struct pci_driver driver = { .probe = cs5530_init_one, }; -static int cs5530_ide_init(void) +static int __init cs5530_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 64330c459bd..9eafcbf444f 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -519,7 +519,7 @@ static struct pci_driver driver = { .probe = cy82c693_init_one, }; -static int cy82c693_ide_init(void) +static int __init cy82c693_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 9f306880491..b408c6c517e 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -185,36 +185,6 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = { .channels = 2, .autodma = AUTODMA, .bootable = OFF_BOARD, - },{ /* 15 */ - .name = "JMB361", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 16 */ - .name = "JMB363", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 17 */ - .name = "JMB365", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 18 */ - .name = "JMB366", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 19 */ - .name = "JMB368", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, } }; @@ -281,11 +251,6 @@ static struct pci_device_id generic_pci_tbl[] = { { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, { PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, /* Must come last. If you add entries adjust this table appropriately and the init_one code */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0}, { 0, }, @@ -298,7 +263,7 @@ static struct pci_driver driver = { .probe = generic_init_one, }; -static int generic_ide_init(void) +static int __init generic_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index b46cb042290..ce7b08f08a0 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -265,7 +265,7 @@ static struct pci_driver driver = { .probe = hpt34x_init_one, }; -static int hpt34x_ide_init(void) +static int __init hpt34x_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 08119da06d5..b486442dd5d 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1613,7 +1613,7 @@ static struct pci_driver driver = { .probe = hpt366_init_one, }; -static int hpt366_ide_init(void) +static int __init hpt366_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index c1cec236ecf..f07bbbed177 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -86,15 +86,16 @@ static int __devinit ata66_jmicron(ide_hwif_t *hwif) { case PORT_PATA0: if (control & (1 << 3)) /* 40/80 pin primary */ - return 1; - return 0; + return 0; + return 1; case PORT_PATA1: if (control5 & (1 << 19)) /* 40/80 pin secondary */ return 0; return 1; case PORT_SATA: - return 1; + break; } + return 1; /* Avoid bogus "control reaches end of non-void function" */ } static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted) @@ -240,11 +241,11 @@ static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_devi } static struct pci_device_id jmicron_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 0}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 1}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 2}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 3}, - { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 4}, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, { 0, }, }; diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index d95714bcee4..8aaea4ea554 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -302,7 +302,7 @@ static struct pci_driver driver = { .probe = ns87415_init_one, }; -static int ns87415_ide_init(void) +static int __init ns87415_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 7a7c2ef78ac..22bbf613f94 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -382,7 +382,7 @@ static struct pci_driver driver = { .probe = opti621_init_one, }; -static int opti621_ide_init(void) +static int __init opti621_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 7cb48576e47..77a9aaa7dab 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -756,7 +756,7 @@ static struct pci_driver driver = { .probe = pdc202new_init_one, }; -static int pdc202new_ide_init(void) +static int __init pdc202new_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 184cdacddeb..143239c093d 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -719,7 +719,7 @@ static struct pci_driver driver = { .probe = pdc202xx_init_one, }; -static int pdc202xx_ide_init(void) +static int __init pdc202xx_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index b1e9a8eba6b..edb37f3d558 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,13 +1,14 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.44 March 20, 2003 + * linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat Inc <alan@redhat.com> + * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com> * * May be copied or modified under the terms of the GNU General Public License * - * PIO mode setting function for Intel chipsets. + * PIO mode setting function for Intel chipsets. * For use instead of BIOS settings. * * 40-41 @@ -25,7 +26,7 @@ * sitre = word42 & 0x4000; secondary * * 44 8421|8421 hdd|hdb - * + * * 48 8421 hdd|hdc|hdb|hda udma enabled * * 0001 hda @@ -353,56 +354,24 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) } /** - * piix_faulty_dma0 - check for DMA0 errata - * @hwif: IDE interface to check - * - * If an ICH/ICH0/ICH2 interface is is operating in multi-word - * DMA mode with 600nS cycle time the IDE PIO prefetch buffer will - * inadvertently provide an extra piece of secondary data to the primary - * device resulting in data corruption. - * - * With such a device this test function returns true. This allows - * our tuning code to follow Intel recommendations and use PIO on - * such devices. - */ - -static int piix_faulty_dma0(ide_hwif_t *hwif) -{ - switch(hwif->pci_dev->device) - { - case PCI_DEVICE_ID_INTEL_82801AA_1: /* ICH */ - case PCI_DEVICE_ID_INTEL_82801AB_1: /* ICH0 */ - case PCI_DEVICE_ID_INTEL_82801BA_8: /* ICH2 */ - case PCI_DEVICE_ID_INTEL_82801BA_9: /* ICH2 */ - return 1; - } - return 0; -} - -/** * piix_config_drive_for_dma - configure drive for DMA * @drive: IDE drive to configure * * Set up a PIIX interface channel for the best available speed. - * We prefer UDMA if it is available and then MWDMA. If DMA is - * not available we switch to PIO and return 0. + * We prefer UDMA if it is available and then MWDMA. If DMA is + * not available we switch to PIO and return 0. */ static int piix_config_drive_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, piix_ratemask(drive)); - - /* Some ICH devices cannot support DMA mode 0 */ - if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive))) - speed = 0; - - /* If no DMA speed was available or the chipset has DMA bugs - then disable DMA and use PIO */ - - if (!speed || no_piix_dma) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = piix_dma_2_pio(XFER_PIO_0 + tspeed); - } + + /* + * If no DMA speed was available or the chipset has DMA bugs + * then disable DMA and use PIO + */ + if (!speed || no_piix_dma) + return 0; (void) piix_tune_chipset(drive, speed); return ide_dma_enable(drive); @@ -425,17 +394,16 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive) if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (piix_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && piix_config_drive_for_dma(drive)) + return hwif->ide_dma_on(drive); goto fast_ata_pio; } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: /* Find best PIO mode. */ - hwif->tuneproc(drive, 255); + (void) hwif->speedproc(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c index 5f6950c2d1d..c1855311052 100644 --- a/drivers/ide/pci/rz1000.c +++ b/drivers/ide/pci/rz1000.c @@ -77,7 +77,7 @@ static struct pci_driver driver = { .probe = rz1000_init_one, }; -static int rz1000_ide_init(void) +static int __init rz1000_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index ff80937d94d..8d762d323f8 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -507,7 +507,7 @@ static struct pci_driver driver = { #endif }; -static int sc1200_ide_init(void) +static int __init sc1200_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index 057548d0720..ea9a28a4585 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -666,7 +666,7 @@ static struct pci_driver driver = { .probe = svwks_init_one, }; -static int svwks_ide_init(void) +static int __init svwks_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index cfad09accf5..b0bf0180927 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -762,8 +762,7 @@ static struct ioc4_submodule ioc4_ide_submodule = { /* .is_remove = ioc4_ide_remove_one, */ }; -static int __devinit -ioc4_ide_init(void) +static int __init ioc4_ide_init(void) { return ioc4_register_submodule(&ioc4_ide_submodule); } diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 697f566fb90..4ff89c7d990 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1096,7 +1096,7 @@ static struct pci_driver driver = { .probe = siimage_init_one, }; -static int siimage_ide_init(void) +static int __init siimage_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 6b313139b5e..1afff659ab5 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -968,7 +968,7 @@ static struct pci_driver driver = { .probe = sis5513_init_one, }; -static int sis5513_ide_init(void) +static int __init sis5513_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 5afefe8692f..170a2619905 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -492,7 +492,7 @@ static struct pci_driver driver = { .probe = sl82c105_init_one, }; -static int sl82c105_ide_init(void) +static int __init sl82c105_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 4a1853af3bb..90e79c0844d 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,9 +1,10 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.11 September 11, 2002 + * linux/drivers/ide/pci/slc90e66.c Version 0.12 May 12, 2006 * * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com> * - * This a look-a-like variation of the ICH0 PIIX4 Ultra-66, + * This is a look-alike variation of the ICH0 PIIX4 Ultra-66, * but this keeps the ISA-Bridge and slots alive. * */ @@ -158,10 +159,8 @@ static int slc90e66_config_drive_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive)); - if (!(speed)) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed); - } + if (!speed) + return 0; (void) slc90e66_tune_chipset(drive, speed); return ide_dma_enable(drive); @@ -176,16 +175,15 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) if (id && (id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (slc90e66_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) + return hwif->ide_dma_on(drive); goto fast_ata_pio; } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - hwif->tuneproc(drive, 5); + (void) hwif->speedproc(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ @@ -255,7 +253,7 @@ static struct pci_driver driver = { .probe = slc90e66_init_one, }; -static int slc90e66_ide_init(void) +static int __init slc90e66_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 56d84931d6d..b13cce1fd1a 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -173,7 +173,7 @@ static struct pci_driver driver = { .probe = triflex_init_one, }; -static int triflex_ide_init(void) +static int __init triflex_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index 2a282529bfc..174b88c4780 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -355,7 +355,7 @@ static struct pci_driver driver = { .probe = trm290_init_one, }; -static int trm290_ide_init(void) +static int __init trm290_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 61f1a9665a7..6fb6e50b823 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -78,6 +78,8 @@ static struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { + { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, + { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, @@ -123,7 +125,7 @@ struct via82cxxx_dev static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) { struct pci_dev *dev = hwif->pci_dev; - struct via82cxxx_dev *vdev = ide_get_hwifdata(hwif); + struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev); u8 t; if (~vdev->via_config->flags & VIA_BAD_AST) { @@ -162,7 +164,7 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) static int via_set_drive(ide_drive_t *drive, u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); - struct via82cxxx_dev *vdev = ide_get_hwifdata(drive->hwif); + struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev); struct ide_timing t, p; unsigned int T, UT; @@ -225,7 +227,7 @@ static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio) static int via82cxxx_ide_dma_check (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - struct via82cxxx_dev *vdev = ide_get_hwifdata(hwif); + struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev); u16 w80 = hwif->udma_four; u16 speed = ide_find_best_mode(drive, @@ -262,6 +264,53 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa) return via_config; } +/* + * Check and handle 80-wire cable presence + */ +static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u) +{ + int i; + + switch (vdev->via_config->flags & VIA_UDMA) { + case VIA_UDMA_66: + for (i = 24; i >= 0; i -= 8) + if (((u >> (i & 16)) & 8) && + ((u >> i) & 0x20) && + (((u >> i) & 7) < 2)) { + /* + * 2x PCI clock and + * UDMA w/ < 3T/cycle + */ + vdev->via_80w |= (1 << (1 - (i >> 4))); + } + break; + + case VIA_UDMA_100: + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || + (((u >> i) & 0x20) && + (((u >> i) & 7) < 4))) { + /* BIOS 80-wire bit or + * UDMA w/ < 60ns/cycle + */ + vdev->via_80w |= (1 << (1 - (i >> 4))); + } + break; + + case VIA_UDMA_133: + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || + (((u >> i) & 0x20) && + (((u >> i) & 7) < 6))) { + /* BIOS 80-wire bit or + * UDMA w/ < 60ns/cycle + */ + vdev->via_80w |= (1 << (1 - (i >> 4))); + } + break; + } +} + /** * init_chipset_via82cxxx - initialization handler * @dev: PCI device @@ -274,14 +323,22 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa) static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const char *name) { struct pci_dev *isa = NULL; + struct via82cxxx_dev *vdev; struct via_isa_bridge *via_config; u8 t, v; - unsigned int u; + u32 u; + + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + printk(KERN_ERR "VP_IDE: out of memory :(\n"); + return -ENOMEM; + } + pci_set_drvdata(dev, vdev); /* * Find the ISA bridge to see how good the IDE is. */ - via_config = via_config_find(&isa); + vdev->via_config = via_config = via_config_find(&isa); /* We checked this earlier so if it fails here deeep badness is involved */ @@ -289,16 +346,17 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const BUG_ON(!via_config->id); /* - * Setup or disable Clk66 if appropriate + * Detect cable and configure Clk66 */ + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + + via_cable_detect(vdev, u); if ((via_config->flags & VIA_UDMA) == VIA_UDMA_66) { /* Enable Clk66 */ - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008); } else if (via_config->flags & VIA_BAD_CLK66) { /* Would cause trouble on 596a and 686 */ - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008); } @@ -367,75 +425,11 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const return 0; } -/* - * Check and handle 80-wire cable presence - */ -static void __devinit via_cable_detect(struct pci_dev *dev, struct via82cxxx_dev *vdev) -{ - unsigned int u; - int i; - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - - switch (vdev->via_config->flags & VIA_UDMA) { - - case VIA_UDMA_66: - for (i = 24; i >= 0; i -= 8) - if (((u >> (i & 16)) & 8) && - ((u >> i) & 0x20) && - (((u >> i) & 7) < 2)) { - /* - * 2x PCI clock and - * UDMA w/ < 3T/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - case VIA_UDMA_100: - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || - (((u >> i) & 0x20) && - (((u >> i) & 7) < 4))) { - /* BIOS 80-wire bit or - * UDMA w/ < 60ns/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - case VIA_UDMA_133: - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || - (((u >> i) & 0x20) && - (((u >> i) & 7) < 6))) { - /* BIOS 80-wire bit or - * UDMA w/ < 60ns/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - } -} - static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) { - struct via82cxxx_dev *vdev = kmalloc(sizeof(struct via82cxxx_dev), - GFP_KERNEL); - struct pci_dev *isa = NULL; + struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev); int i; - if (vdev == NULL) { - printk(KERN_ERR "VP_IDE: out of memory :(\n"); - return; - } - - memset(vdev, 0, sizeof(struct via82cxxx_dev)); - ide_set_hwifdata(hwif, vdev); - - vdev->via_config = via_config_find(&isa); - via_cable_detect(hwif->pci_dev, vdev); - hwif->autodma = 0; hwif->tuneproc = &via82cxxx_tune_drive; @@ -512,6 +506,7 @@ static struct pci_device_id via_pci_tbl[] = { { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { 0, }, }; MODULE_DEVICE_TABLE(pci, via_pci_tbl); @@ -522,7 +517,7 @@ static struct pci_driver driver = { .probe = via_init_one, }; -static int via_ide_init(void) +static int __init via_ide_init(void) { return ide_pci_register_driver(&driver); } diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index e68b80b7340..4325aac7733 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -490,11 +490,11 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return -ENOMEM; } - cmd->command_orb_dma = dma_map_single(&hi->host->device, + cmd->command_orb_dma = dma_map_single(hi->host->device.parent, &cmd->command_orb, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - cmd->sge_dma = dma_map_single(&hi->host->device, + cmd->sge_dma = dma_map_single(hi->host->device.parent, &cmd->scatter_gather_element, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); @@ -516,10 +516,11 @@ static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu) if (!list_empty(&lu->cmd_orb_completed)) list_for_each_safe(lh, next, &lu->cmd_orb_completed) { cmd = list_entry(lh, struct sbp2_command_info, list); - dma_unmap_single(&host->device, cmd->command_orb_dma, + dma_unmap_single(host->device.parent, + cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - dma_unmap_single(&host->device, cmd->sge_dma, + dma_unmap_single(host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); kfree(cmd); @@ -601,17 +602,17 @@ static void sbp2util_mark_command_completed(struct sbp2_lu *lu, if (cmd->cmd_dma) { if (cmd->dma_type == CMD_DMA_SINGLE) - dma_unmap_single(&host->device, cmd->cmd_dma, + dma_unmap_single(host->device.parent, cmd->cmd_dma, cmd->dma_size, cmd->dma_dir); else if (cmd->dma_type == CMD_DMA_PAGE) - dma_unmap_page(&host->device, cmd->cmd_dma, + dma_unmap_page(host->device.parent, cmd->cmd_dma, cmd->dma_size, cmd->dma_dir); /* XXX: Check for CMD_DMA_NONE bug */ cmd->dma_type = CMD_DMA_NONE; cmd->cmd_dma = 0; } if (cmd->sge_buffer) { - dma_unmap_sg(&host->device, cmd->sge_buffer, + dma_unmap_sg(host->device.parent, cmd->sge_buffer, cmd->dma_size, cmd->dma_dir); cmd->sge_buffer = NULL; } @@ -836,37 +837,37 @@ static int sbp2_start_device(struct sbp2_lu *lu) struct sbp2_fwhost_info *hi = lu->hi; int error; - lu->login_response = dma_alloc_coherent(&hi->host->device, + lu->login_response = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_login_response), &lu->login_response_dma, GFP_KERNEL); if (!lu->login_response) goto alloc_fail; - lu->query_logins_orb = dma_alloc_coherent(&hi->host->device, + lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_query_logins_orb), &lu->query_logins_orb_dma, GFP_KERNEL); if (!lu->query_logins_orb) goto alloc_fail; - lu->query_logins_response = dma_alloc_coherent(&hi->host->device, + lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_query_logins_response), &lu->query_logins_response_dma, GFP_KERNEL); if (!lu->query_logins_response) goto alloc_fail; - lu->reconnect_orb = dma_alloc_coherent(&hi->host->device, + lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_reconnect_orb), &lu->reconnect_orb_dma, GFP_KERNEL); if (!lu->reconnect_orb) goto alloc_fail; - lu->logout_orb = dma_alloc_coherent(&hi->host->device, + lu->logout_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_logout_orb), &lu->logout_orb_dma, GFP_KERNEL); if (!lu->logout_orb) goto alloc_fail; - lu->login_orb = dma_alloc_coherent(&hi->host->device, + lu->login_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_login_orb), &lu->login_orb_dma, GFP_KERNEL); if (!lu->login_orb) @@ -929,32 +930,32 @@ static void sbp2_remove_device(struct sbp2_lu *lu) list_del(&lu->lu_list); if (lu->login_response) - dma_free_coherent(&hi->host->device, + dma_free_coherent(hi->host->device.parent, sizeof(struct sbp2_login_response), lu->login_response, lu->login_response_dma); if (lu->login_orb) - dma_free_coherent(&hi->host->device, + dma_free_coherent(hi->host->device.parent, sizeof(struct sbp2_login_orb), lu->login_orb, lu->login_orb_dma); if (lu->reconnect_orb) - dma_free_coherent(&hi->host->device, + dma_free_coherent(hi->host->device.parent, sizeof(struct sbp2_reconnect_orb), lu->reconnect_orb, lu->reconnect_orb_dma); if (lu->logout_orb) - dma_free_coherent(&hi->host->device, + dma_free_coherent(hi->host->device.parent, sizeof(struct sbp2_logout_orb), lu->logout_orb, lu->logout_orb_dma); if (lu->query_logins_orb) - dma_free_coherent(&hi->host->device, + dma_free_coherent(hi->host->device.parent, sizeof(struct sbp2_query_logins_orb), lu->query_logins_orb, lu->query_logins_orb_dma); if (lu->query_logins_response) - dma_free_coherent(&hi->host->device, + dma_free_coherent(hi->host->device.parent, sizeof(struct sbp2_query_logins_response), lu->query_logins_response, lu->query_logins_response_dma); @@ -1445,7 +1446,7 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, cmd->dma_size = sgpnt[0].length; cmd->dma_type = CMD_DMA_PAGE; - cmd->cmd_dma = dma_map_page(&hi->host->device, + cmd->cmd_dma = dma_map_page(hi->host->device.parent, sgpnt[0].page, sgpnt[0].offset, cmd->dma_size, cmd->dma_dir); @@ -1457,8 +1458,8 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, &cmd->scatter_gather_element[0]; u32 sg_count, sg_len; dma_addr_t sg_addr; - int i, count = dma_map_sg(&hi->host->device, sgpnt, scsi_use_sg, - dma_dir); + int i, count = dma_map_sg(hi->host->device.parent, sgpnt, + scsi_use_sg, dma_dir); cmd->dma_size = scsi_use_sg; cmd->sge_buffer = sgpnt; @@ -1508,7 +1509,8 @@ static void sbp2_prep_command_orb_no_sg(struct sbp2_command_orb *orb, cmd->dma_dir = dma_dir; cmd->dma_size = scsi_request_bufflen; cmd->dma_type = CMD_DMA_SINGLE; - cmd->cmd_dma = dma_map_single(&hi->host->device, scsi_request_buffer, + cmd->cmd_dma = dma_map_single(hi->host->device.parent, + scsi_request_buffer, cmd->dma_size, cmd->dma_dir); orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); orb->misc |= ORB_SET_DIRECTION(orb_direction); @@ -1626,10 +1628,11 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu, size_t length; unsigned long flags; - dma_sync_single_for_device(&hi->host->device, cmd->command_orb_dma, + dma_sync_single_for_device(hi->host->device.parent, + cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - dma_sync_single_for_device(&hi->host->device, cmd->sge_dma, + dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); @@ -1655,14 +1658,15 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu, * The target's fetch agent may or may not have read this * previous ORB yet. */ - dma_sync_single_for_cpu(&hi->host->device, last_orb_dma, + dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma); wmb(); /* Tells hardware that this pointer is valid */ last_orb->next_ORB_hi = 0; - dma_sync_single_for_device(&hi->host->device, last_orb_dma, + dma_sync_single_for_device(hi->host->device.parent, + last_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); addr += SBP2_DOORBELL_OFFSET; @@ -1790,10 +1794,11 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, else cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo); if (cmd) { - dma_sync_single_for_cpu(&hi->host->device, cmd->command_orb_dma, + dma_sync_single_for_cpu(hi->host->device.parent, + cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - dma_sync_single_for_cpu(&hi->host->device, cmd->sge_dma, + dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); /* Grab SCSI command pointers and check status. */ @@ -1882,16 +1887,6 @@ static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, if (unlikely(SCpnt->device->lun)) goto done; - /* handle the request sense command here (auto-request sense) */ - if (SCpnt->cmnd[0] == REQUEST_SENSE) { - memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, - SCpnt->request_bufflen); - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - sbp2scsi_complete_command(lu, SBP2_SCSI_STATUS_GOOD, SCpnt, - done); - return 0; - } - if (unlikely(!hpsb_node_entry_valid(lu->ne))) { SBP2_ERR("Bus reset in progress - rejecting command"); result = DID_BUS_BUSY << 16; @@ -1931,10 +1926,11 @@ static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status) while (!list_empty(&lu->cmd_orb_inuse)) { lh = lu->cmd_orb_inuse.next; cmd = list_entry(lh, struct sbp2_command_info, list); - dma_sync_single_for_cpu(&hi->host->device, cmd->command_orb_dma, + dma_sync_single_for_cpu(hi->host->device.parent, + cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - dma_sync_single_for_cpu(&hi->host->device, cmd->sge_dma, + dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(lu, cmd); @@ -2024,6 +2020,8 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev) blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); sdev->use_10_for_rw = 1; + if (sdev->type == TYPE_ROM) + sdev->use_10_for_ms = 1; if (sdev->type == TYPE_DISK && lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) sdev->skip_ms_page_8 = 1; @@ -2059,11 +2057,12 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) spin_lock_irqsave(&lu->cmd_orb_lock, flags); cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt); if (cmd) { - dma_sync_single_for_cpu(&hi->host->device, + dma_sync_single_for_cpu(hi->host->device.parent, cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - dma_sync_single_for_cpu(&hi->host->device, cmd->sge_dma, + dma_sync_single_for_cpu(hi->host->device.parent, + cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(lu, cmd); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 533193d4e5d..9e0ab048c87 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1088,10 +1088,21 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) *sin = iw_event->local_addr; sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; *sin = iw_event->remote_addr; - if (iw_event->status) - event.event = RDMA_CM_EVENT_REJECTED; - else + switch (iw_event->status) { + case 0: event.event = RDMA_CM_EVENT_ESTABLISHED; + break; + case -ECONNRESET: + case -ECONNREFUSED: + event.event = RDMA_CM_EVENT_REJECTED; + break; + case -ETIMEDOUT: + event.event = RDMA_CM_EVENT_UNREACHABLE; + break; + default: + event.event = RDMA_CM_EVENT_CONNECT_ERROR; + break; + } break; case IW_CM_EVENT_ESTABLISHED: event.event = RDMA_CM_EVENT_ESTABLISHED; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 81a5cdc5733..e2e8d329b44 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -209,10 +209,21 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) { if (!ctx->backlog) { ret = -EDQUOT; + kfree(uevent); goto out; } ctx->backlog--; + } else if (!ctx->uid) { + /* + * We ignore events for new connections until userspace has set + * their context. This can only happen if an error occurs on a + * new connection before the user accepts it. This is okay, + * since the accept will just fail later. + */ + kfree(uevent); + goto out; } + list_add_tail(&uevent->list, &ctx->file->event_list); wake_up_interruptible(&ctx->file->poll_wait); out: diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 93995b658d9..6074c897f51 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -344,8 +344,11 @@ int ehca_destroy_cq(struct ib_cq *cq) unsigned long flags; spin_lock_irqsave(&ehca_cq_idr_lock, flags); - while (my_cq->nr_callbacks) + while (my_cq->nr_callbacks) { + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); yield(); + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + } idr_remove(&ehca_cq_idr, my_cq->token); spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index e1b618c5f68..b7be950ab47 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -50,7 +50,7 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) ib_device); struct hipz_query_hca *rblock; - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -110,7 +110,7 @@ int ehca_query_port(struct ib_device *ibdev, ib_device); struct hipz_query_port *rblock; - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -179,7 +179,7 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) return -EINVAL; } - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -212,7 +212,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, return -EINVAL; } - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index c3ea746e904..c069be8cbcb 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -138,7 +138,7 @@ int ehca_error_data(struct ehca_shca *shca, void *data, u64 *rblock; unsigned long block_count; - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC); if (!rblock) { ehca_err(&shca->ib_device, "Cannot allocate rblock memory."); ret = -ENOMEM; @@ -440,7 +440,8 @@ void ehca_tasklet_eq(unsigned long data) cq = idr_find(&ehca_cq_idr, token); if (cq == NULL) { - spin_unlock(&ehca_cq_idr_lock); + spin_unlock_irqrestore(&ehca_cq_idr_lock, + flags); break; } diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index 3720e3032cc..cd7789f0d08 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -180,10 +180,10 @@ int ehca_mmap_register(u64 physical,void **mapped, int ehca_munmap(unsigned long addr, size_t len); #ifdef CONFIG_PPC_64K_PAGES -void *ehca_alloc_fw_ctrlblock(void); +void *ehca_alloc_fw_ctrlblock(gfp_t flags); void ehca_free_fw_ctrlblock(void *ptr); #else -#define ehca_alloc_fw_ctrlblock() ((void *) get_zeroed_page(GFP_KERNEL)) +#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags)) #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr)) #endif diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index cc47e4c13a1..6574fbbaead 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -106,9 +106,9 @@ static struct timer_list poll_eqs_timer; #ifdef CONFIG_PPC_64K_PAGES static struct kmem_cache *ctblk_cache = NULL; -void *ehca_alloc_fw_ctrlblock(void) +void *ehca_alloc_fw_ctrlblock(gfp_t flags) { - void *ret = kmem_cache_zalloc(ctblk_cache, GFP_KERNEL); + void *ret = kmem_cache_zalloc(ctblk_cache, flags); if (!ret) ehca_gen_err("Out of memory for ctblk"); return ret; @@ -206,7 +206,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) u64 h_ret; struct hipz_query_hca *rblock; - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!rblock) { ehca_gen_err("Cannot allocate rblock memory."); return -ENOMEM; @@ -258,7 +258,7 @@ static int init_node_guid(struct ehca_shca *shca) int ret = 0; struct hipz_query_hca *rblock; - rblock = ehca_alloc_fw_ctrlblock(); + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!rblock) { ehca_err(&shca->ib_device, "Can't allocate rblock memory."); return -ENOMEM; @@ -469,7 +469,7 @@ static ssize_t ehca_show_##name(struct device *dev, \ \ shca = dev->driver_data; \ \ - rblock = ehca_alloc_fw_ctrlblock(); \ + rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); \ if (!rblock) { \ dev_err(dev, "Can't allocate rblock memory."); \ return 0; \ diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 0a5e2214cc5..cfb362a1029 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -1013,7 +1013,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, u32 i; u64 *kpage; - kpage = ehca_alloc_fw_ctrlblock(); + kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!kpage) { ehca_err(&shca->ib_device, "kpage alloc failed"); ret = -ENOMEM; @@ -1124,7 +1124,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, ehca_mrmw_map_acl(acl, &hipz_acl); ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); - kpage = ehca_alloc_fw_ctrlblock(); + kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!kpage) { ehca_err(&shca->ib_device, "kpage alloc failed"); ret = -ENOMEM; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index c6c9cef203e..34b85556d01 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -807,7 +807,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, unsigned long spl_flags = 0; /* do query_qp to obtain current attr values */ - mqpcb = ehca_alloc_fw_ctrlblock(); + mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!mqpcb) { ehca_err(ibqp->device, "Could not get zeroed page for mqpcb " "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num); @@ -1273,7 +1273,7 @@ int ehca_query_qp(struct ib_qp *qp, return -EINVAL; } - qpcb = ehca_alloc_fw_ctrlblock(); + qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!qpcb) { ehca_err(qp->device,"Out of memory for qpcb " "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num); diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 283d50b76c3..1159c8a0f2c 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -54,6 +54,10 @@ enum { MTHCA_CQ_ENTRY_SIZE = 0x20 }; +enum { + MTHCA_ATOMIC_BYTE_LEN = 8 +}; + /* * Must be packed because start is 64 bits but only aligned to 32 bits. */ @@ -599,11 +603,11 @@ static inline int mthca_poll_one(struct mthca_dev *dev, break; case MTHCA_OPCODE_ATOMIC_CS: entry->opcode = IB_WC_COMP_SWAP; - entry->byte_len = be32_to_cpu(cqe->byte_cnt); + entry->byte_len = MTHCA_ATOMIC_BYTE_LEN; break; case MTHCA_OPCODE_ATOMIC_FA: entry->opcode = IB_WC_FETCH_ADD; - entry->byte_len = be32_to_cpu(cqe->byte_cnt); + entry->byte_len = MTHCA_ATOMIC_BYTE_LEN; break; case MTHCA_OPCODE_BIND_MW: entry->opcode = IB_WC_BIND_MW; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 15cc2f6eb47..6b19645d946 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -232,7 +232,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj) list_for_each_entry(chunk, &icm->chunk_list, list) { for (i = 0; i < chunk->npages; ++i) { - if (chunk->mem[i].length >= offset) { + if (chunk->mem[i].length > offset) { page = chunk->mem[i].page; goto out; } diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 7ec7c4b937f..7b96751695e 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1100,10 +1100,11 @@ static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags, struct mthca_fmr *fmr; int err; - fmr = kmemdup(fmr_attr, sizeof *fmr, GFP_KERNEL); + fmr = kmalloc(sizeof *fmr, GFP_KERNEL); if (!fmr) return ERR_PTR(-ENOMEM); + memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr); err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num, convert_access(mr_access_flags), fmr); diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index d844a2569b4..5f5214c0337 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -429,13 +429,18 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m { struct mthca_dev *dev = to_mdev(ibqp->device); struct mthca_qp *qp = to_mqp(ibqp); - int err; - struct mthca_mailbox *mailbox; + int err = 0; + struct mthca_mailbox *mailbox = NULL; struct mthca_qp_param *qp_param; struct mthca_qp_context *context; int mthca_state; u8 status; + if (qp->state == IB_QPS_RESET) { + qp_attr->qp_state = IB_QPS_RESET; + goto done; + } + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); if (IS_ERR(mailbox)) return PTR_ERR(mailbox); @@ -454,7 +459,6 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m mthca_state = be32_to_cpu(context->flags) >> 28; qp_attr->qp_state = to_ib_qp_state(mthca_state); - qp_attr->cur_qp_state = qp_attr->qp_state; qp_attr->path_mtu = context->mtu_msgmax >> 5; qp_attr->path_mig_state = to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3); @@ -464,11 +468,6 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m qp_attr->dest_qp_num = be32_to_cpu(context->remote_qpn) & 0xffffff; qp_attr->qp_access_flags = to_ib_qp_access_flags(be32_to_cpu(context->params2)); - qp_attr->cap.max_send_wr = qp->sq.max; - qp_attr->cap.max_recv_wr = qp->rq.max; - qp_attr->cap.max_send_sge = qp->sq.max_gs; - qp_attr->cap.max_recv_sge = qp->rq.max_gs; - qp_attr->cap.max_inline_data = qp->max_inline_data; if (qp->transport == RC || qp->transport == UC) { to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); @@ -495,7 +494,16 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7; qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5; qp_attr->alt_timeout = context->alt_path.ackto >> 3; - qp_init_attr->cap = qp_attr->cap; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_send_wr = qp->sq.max; + qp_attr->cap.max_recv_wr = qp->rq.max; + qp_attr->cap.max_send_sge = qp->sq.max_gs; + qp_attr->cap.max_recv_sge = qp->rq.max_gs; + qp_attr->cap.max_inline_data = qp->max_inline_data; + + qp_init_attr->cap = qp_attr->cap; out: mthca_free_mailbox(dev, mailbox); diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 9b2041e25d5..dd221eda3ea 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -177,7 +177,7 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, * - if yes, the mtask is recycled at iscsi_complete_pdu * - if no, the mtask is recycled at iser_snd_completion */ - if (error && error != -EAGAIN) + if (error && error != -ENOBUFS) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error; @@ -241,7 +241,7 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn, error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask); iscsi_iser_ctask_xmit_exit: - if (error && error != -EAGAIN) + if (error && error != -ENOBUFS) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error; } diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index e73c87b9be4..0a7d1ab60e6 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -304,18 +304,14 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) static int iser_check_xmit(struct iscsi_conn *conn, void *task) { - int rc = 0; struct iscsi_iser_conn *iser_conn = conn->dd_data; - write_lock_bh(conn->recv_lock); if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) == ISER_QP_MAX_REQ_DTOS) { - iser_dbg("%ld can't xmit task %p, suspending tx\n",jiffies,task); - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - rc = -EAGAIN; + iser_dbg("%ld can't xmit task %p\n",jiffies,task); + return -ENOBUFS; } - write_unlock_bh(conn->recv_lock); - return rc; + return 0; } @@ -340,7 +336,7 @@ int iser_send_command(struct iscsi_conn *conn, return -EPERM; } if (iser_check_xmit(conn, ctask)) - return -EAGAIN; + return -ENOBUFS; edtl = ntohl(hdr->data_length); @@ -426,7 +422,7 @@ int iser_send_data_out(struct iscsi_conn *conn, } if (iser_check_xmit(conn, ctask)) - return -EAGAIN; + return -ENOBUFS; itt = ntohl(hdr->itt); data_seg_len = ntoh24(hdr->dlength); @@ -498,7 +494,7 @@ int iser_send_control(struct iscsi_conn *conn, } if (iser_check_xmit(conn,mtask)) - return -EAGAIN; + return -ENOBUFS; /* build the tx desc regd header and add it to the tx desc dto */ mdesc->type = ISCSI_TX_CONTROL; @@ -605,6 +601,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn; struct iscsi_conn *conn = iser_conn->iscsi_conn; struct iscsi_mgmt_task *mtask; + int resume_tx = 0; iser_dbg("Initiator, Data sent dto=0x%p\n", dto); @@ -613,15 +610,16 @@ void iser_snd_completion(struct iser_desc *tx_desc) if (tx_desc->type == ISCSI_TX_DATAOUT) kmem_cache_free(ig.desc_cache, tx_desc); + if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) == + ISER_QP_MAX_REQ_DTOS) + resume_tx = 1; + atomic_dec(&ib_conn->post_send_buf_count); - write_lock(conn->recv_lock); - if (conn->suspend_tx) { + if (resume_tx) { iser_dbg("%ld resuming tx\n",jiffies); - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); scsi_queue_work(conn->session->host, &conn->xmitwork); } - write_unlock(conn->recv_lock); if (tx_desc->type == ISCSI_TX_CONTROL) { /* this arithmetic is legal by libiscsi dd_data allocation */ diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index cdecbf5911c..72611fd1510 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1621,18 +1621,30 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) switch (token) { case SRP_OPT_ID_EXT: p = match_strdup(args); + if (!p) { + ret = -ENOMEM; + goto out; + } target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_IOC_GUID: p = match_strdup(args); + if (!p) { + ret = -ENOMEM; + goto out; + } target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_DGID: p = match_strdup(args); + if (!p) { + ret = -ENOMEM; + goto out; + } if (strlen(p) != 32) { printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); kfree(p); @@ -1656,6 +1668,10 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_SERVICE_ID: p = match_strdup(args); + if (!p) { + ret = -ENOMEM; + goto out; + } target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; @@ -1693,6 +1709,10 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_INITIATOR_EXT: p = match_strdup(args); + if (!p) { + ret = -ENOMEM; + goto out; + } target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index 54adba2d8ed..d9ca55891cd 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -16,6 +16,7 @@ static int i8042_aux_irq = -1; #define I8042_MUX_PHYS_DESC "sparcps2/serio%d" static void __iomem *kbd_iobase; +static struct resource *kbd_res; #define I8042_COMMAND_REG (kbd_iobase + 0x64UL) #define I8042_DATA_REG (kbd_iobase + 0x60UL) @@ -60,6 +61,7 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev i8042_kbd_irq = irq; kbd_iobase = of_ioremap(&kbd->resource[0], 0, 8, "kbd"); + kbd_res = &kbd->resource[0]; } else if (!strcmp(dp->name, OBP_PS2MS_NAME1) || !strcmp(dp->name, OBP_PS2MS_NAME2)) { struct of_device *ms = of_find_device_by_node(dp); @@ -77,7 +79,7 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev static int __devexit sparc_i8042_remove(struct of_device *op) { - of_iounmap(kbd_iobase, 8); + of_iounmap(kbd_res, kbd_iobase, 8); return 0; } @@ -119,7 +121,7 @@ static int __init i8042_platform_init(void) if (i8042_kbd_irq == -1 || i8042_aux_irq == -1) { if (kbd_iobase) { - of_iounmap(kbd_iobase, 8); + of_iounmap(kbd_res, kbd_iobase, 8); kbd_iobase = (void __iomem *) NULL; } return -ENODEV; diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 95eff3b2917..4f75cce6fdf 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -356,16 +356,17 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv) { unsigned long flags; unsigned i; - static struct cardstate *ret = NULL; + struct cardstate *ret = NULL; spin_lock_irqsave(&drv->lock, flags); for (i = 0; i < drv->minors; ++i) { if (!(drv->flags[i] & VALID_MINOR)) { - drv->flags[i] = VALID_MINOR; - ret = drv->cs + i; - } - if (ret) + if (try_module_get(drv->owner)) { + drv->flags[i] = VALID_MINOR; + ret = drv->cs + i; + } break; + } } spin_unlock_irqrestore(&drv->lock, flags); return ret; @@ -376,6 +377,8 @@ static void free_cs(struct cardstate *cs) unsigned long flags; struct gigaset_driver *drv = cs->driver; spin_lock_irqsave(&drv->lock, flags); + if (drv->flags[cs->minor_index] & VALID_MINOR) + module_put(drv->owner); drv->flags[cs->minor_index] = 0; spin_unlock_irqrestore(&drv->lock, flags); } @@ -579,7 +582,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else { - warn("could not allocate skb\n"); + warn("could not allocate skb"); bcs->inputstate |= INS_skip_frame; } @@ -632,17 +635,25 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, int i; gig_dbg(DEBUG_INIT, "allocating cs"); - cs = alloc_cs(drv); - if (!cs) - goto error; + if (!(cs = alloc_cs(drv))) { + err("maximum number of devices exceeded"); + return NULL; + } + mutex_init(&cs->mutex); + mutex_lock(&cs->mutex); + gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); - if (!cs->bcs) + if (!cs->bcs) { + err("out of memory"); goto error; + } gig_dbg(DEBUG_INIT, "allocating inbuf"); cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); - if (!cs->inbuf) + if (!cs->inbuf) { + err("out of memory"); goto error; + } cs->cs_init = 0; cs->channels = channels; @@ -654,8 +665,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, spin_lock_init(&cs->ev_lock); cs->ev_tail = 0; cs->ev_head = 0; - mutex_init(&cs->mutex); - mutex_lock(&cs->mutex); tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs); @@ -684,8 +693,10 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, for (i = 0; i < channels; ++i) { gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); - if (!gigaset_initbcs(cs->bcs + i, cs, i)) + if (!gigaset_initbcs(cs->bcs + i, cs, i)) { + err("could not allocate channel %d data", i); goto error; + } } ++cs->cs_init; @@ -720,8 +731,10 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, make_valid(cs, VALID_ID); ++cs->cs_init; gig_dbg(DEBUG_INIT, "setting up hw"); - if (!cs->ops->initcshw(cs)) + if (!cs->ops->initcshw(cs)) { + err("could not allocate device specific data"); goto error; + } ++cs->cs_init; @@ -743,8 +756,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, mutex_unlock(&cs->mutex); return cs; -error: if (cs) - mutex_unlock(&cs->mutex); +error: + mutex_unlock(&cs->mutex); gig_dbg(DEBUG_INIT, "failed"); gigaset_freecs(cs); return NULL; @@ -1040,7 +1053,6 @@ void gigaset_freedriver(struct gigaset_driver *drv) spin_unlock_irqrestore(&driver_lock, flags); gigaset_if_freedriver(drv); - module_put(drv->owner); kfree(drv->cs); kfree(drv->flags); @@ -1072,10 +1084,6 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, if (!drv) return NULL; - if (!try_module_get(owner)) - goto out1; - - drv->cs = NULL; drv->have_tty = 0; drv->minor = minor; drv->minors = minors; @@ -1087,11 +1095,11 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL); if (!drv->cs) - goto out2; + goto error; drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); if (!drv->flags) - goto out3; + goto error; for (i = 0; i < minors; ++i) { drv->flags[i] = 0; @@ -1108,11 +1116,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, return drv; -out3: +error: kfree(drv->cs); -out2: - module_put(owner); -out1: kfree(drv); return NULL; } diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 1726131b20b..4e3f127e400 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -2339,6 +2339,7 @@ static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_s rs->state = CCPResetIdle; rs->is = is; rs->id = id; + init_timer(&rs->timer); rs->timer.data = (unsigned long)rs; rs->timer.function = isdn_ppp_ccp_timer_callback; is->reset->rs[id] = rs; diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 930e04ce1af..2db1ca4c680 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -52,6 +52,8 @@ #define KVM_MAX_VCPUS 1 #define KVM_MEMORY_SLOTS 4 #define KVM_NUM_MMU_PAGES 256 +#define KVM_MIN_FREE_MMU_PAGES 5 +#define KVM_REFILL_PAGES 25 #define FX_IMAGE_SIZE 512 #define FX_IMAGE_ALIGN 16 @@ -89,14 +91,54 @@ typedef unsigned long hva_t; typedef u64 hpa_t; typedef unsigned long hfn_t; +#define NR_PTE_CHAIN_ENTRIES 5 + +struct kvm_pte_chain { + u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES]; + struct hlist_node link; +}; + +/* + * kvm_mmu_page_role, below, is defined as: + * + * bits 0:3 - total guest paging levels (2-4, or zero for real mode) + * bits 4:7 - page table level for this shadow (1-4) + * bits 8:9 - page table quadrant for 2-level guests + * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) + */ +union kvm_mmu_page_role { + unsigned word; + struct { + unsigned glevels : 4; + unsigned level : 4; + unsigned quadrant : 2; + unsigned pad_for_nice_hex_output : 6; + unsigned metaphysical : 1; + }; +}; + struct kvm_mmu_page { struct list_head link; + struct hlist_node hash_link; + + /* + * The following two entries are used to key the shadow page in the + * hash table. + */ + gfn_t gfn; + union kvm_mmu_page_role role; + hpa_t page_hpa; unsigned long slot_bitmap; /* One bit set per slot which has memory * in this shadow page. */ int global; /* Set if all ptes in this page are global */ - u64 *parent_pte; + int multimapped; /* More than one parent_pte? */ + int root_count; /* Currently serving as active root */ + union { + u64 *parent_pte; /* !multimapped */ + struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */ + }; }; struct vmcs { @@ -117,14 +159,26 @@ struct kvm_vcpu; struct kvm_mmu { void (*new_cr3)(struct kvm_vcpu *vcpu); int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err); - void (*inval_page)(struct kvm_vcpu *vcpu, gva_t gva); void (*free)(struct kvm_vcpu *vcpu); gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva); hpa_t root_hpa; int root_level; int shadow_root_level; + + u64 *pae_root; }; +#define KVM_NR_MEM_OBJS 20 + +struct kvm_mmu_memory_cache { + int nobjs; + void *objects[KVM_NR_MEM_OBJS]; +}; + +/* + * We don't want allocation failures within the mmu code, so we preallocate + * enough memory for a single page fault in a cache. + */ struct kvm_guest_debug { int enabled; unsigned long bp[4]; @@ -173,6 +227,7 @@ struct kvm_vcpu { struct mutex mutex; int cpu; int launched; + int interrupt_window_open; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) unsigned long irq_pending[NR_IRQ_WORDS]; @@ -184,8 +239,10 @@ struct kvm_vcpu { unsigned long cr3; unsigned long cr4; unsigned long cr8; + u64 pdptrs[4]; /* pae */ u64 shadow_efer; u64 apic_base; + u64 ia32_misc_enable_msr; int nmsrs; struct vmx_msr_entry *guest_msrs; struct vmx_msr_entry *host_msrs; @@ -194,6 +251,12 @@ struct kvm_vcpu { struct kvm_mmu_page page_header_buf[KVM_NUM_MMU_PAGES]; struct kvm_mmu mmu; + struct kvm_mmu_memory_cache mmu_pte_chain_cache; + struct kvm_mmu_memory_cache mmu_rmap_desc_cache; + + gfn_t last_pt_write_gfn; + int last_pt_write_count; + struct kvm_guest_debug guest_debug; char fx_buf[FX_BUF_SIZE]; @@ -231,10 +294,16 @@ struct kvm { spinlock_t lock; /* protects everything except vcpus */ int nmemslots; struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS]; + /* + * Hash table of struct kvm_mmu_page. + */ struct list_head active_mmu_pages; + int n_free_mmu_pages; + struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; struct kvm_vcpu vcpus[KVM_MAX_VCPUS]; int memory_config_version; int busy; + unsigned long rmap_overflow; }; struct kvm_stat { @@ -247,6 +316,9 @@ struct kvm_stat { u32 io_exits; u32 mmio_exits; u32 signal_exits; + u32 irq_window_exits; + u32 halt_exits; + u32 request_irq_exits; u32 irq_exits; }; @@ -278,8 +350,8 @@ struct kvm_arch_ops { struct kvm_segment *var, int seg); void (*set_segment)(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); - int (*is_long_mode)(struct kvm_vcpu *vcpu); void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); + void (*decache_cr0_cr4_guest_bits)(struct kvm_vcpu *vcpu); void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu, unsigned long cr0); @@ -320,10 +392,11 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module); void kvm_exit_arch(void); void kvm_mmu_destroy(struct kvm_vcpu *vcpu); -int kvm_mmu_init(struct kvm_vcpu *vcpu); +int kvm_mmu_create(struct kvm_vcpu *vcpu); +int kvm_mmu_setup(struct kvm_vcpu *vcpu); int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); -void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot); +void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot); hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa); #define HPA_MSB ((sizeof(hpa_t) * 8) - 1) @@ -375,9 +448,8 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); -#ifdef CONFIG_X86_64 -void set_efer(struct kvm_vcpu *vcpu, u64 efer); -#endif +int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); +int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data); void fx_init(struct kvm_vcpu *vcpu); @@ -397,12 +469,34 @@ int kvm_write_guest(struct kvm_vcpu *vcpu, unsigned long segment_base(u16 selector); +void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes); +void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes); +int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); +void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); + +static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, + u32 error_code) +{ + if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) + kvm_mmu_free_some_pages(vcpu); + return vcpu->mmu.page_fault(vcpu, gva, error_code); +} + static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn) { struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL; } +static inline int is_long_mode(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_X86_64 + return vcpu->shadow_efer & EFER_LME; +#else + return 0; +#endif +} + static inline int is_pae(struct kvm_vcpu *vcpu) { return vcpu->cr4 & CR4_PAE_MASK; @@ -533,19 +627,4 @@ static inline u32 get_rdx_init_val(void) #define TSS_REDIRECTION_SIZE (256 / 8) #define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) -#ifdef CONFIG_X86_64 - -/* - * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64. Therefore - * we need to allocate shadow page tables in the first 4GB of memory, which - * happens to fit the DMA32 zone. - */ -#define GFP_KVM_MMU (GFP_KERNEL | __GFP_DMA32) - -#else - -#define GFP_KVM_MMU GFP_KERNEL - -#endif - #endif diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index fd1bb870545..b10972ed0c9 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -58,6 +58,9 @@ static struct kvm_stats_debugfs_item { { "io_exits", &kvm_stat.io_exits }, { "mmio_exits", &kvm_stat.mmio_exits }, { "signal_exits", &kvm_stat.signal_exits }, + { "irq_window", &kvm_stat.irq_window_exits }, + { "halt_exits", &kvm_stat.halt_exits }, + { "request_irq", &kvm_stat.request_irq_exits }, { "irq_exits", &kvm_stat.irq_exits }, { 0, 0 } }; @@ -113,6 +116,11 @@ unsigned long segment_base(u16 selector) } EXPORT_SYMBOL_GPL(segment_base); +static inline int valid_vcpu(int n) +{ + return likely(n >= 0 && n < KVM_MAX_VCPUS); +} + int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size, @@ -222,6 +230,7 @@ static int kvm_dev_open(struct inode *inode, struct file *filp) struct kvm_vcpu *vcpu = &kvm->vcpus[i]; mutex_init(&vcpu->mutex); + vcpu->kvm = kvm; vcpu->mmu.root_hpa = INVALID_PAGE; INIT_LIST_HEAD(&vcpu->free_pages); } @@ -240,7 +249,8 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free, if (!dont || free->phys_mem != dont->phys_mem) if (free->phys_mem) { for (i = 0; i < free->npages; ++i) - __free_page(free->phys_mem[i]); + if (free->phys_mem[i]) + __free_page(free->phys_mem[i]); vfree(free->phys_mem); } @@ -262,8 +272,10 @@ static void kvm_free_physmem(struct kvm *kvm) static void kvm_free_vcpu(struct kvm_vcpu *vcpu) { - kvm_arch_ops->vcpu_free(vcpu); + vcpu_load(vcpu->kvm, vcpu_slot(vcpu)); kvm_mmu_destroy(vcpu); + vcpu_put(vcpu); + kvm_arch_ops->vcpu_free(vcpu); } static void kvm_free_vcpus(struct kvm *kvm) @@ -289,14 +301,17 @@ static void inject_gp(struct kvm_vcpu *vcpu) kvm_arch_ops->inject_gp(vcpu, 0); } -static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu, - unsigned long cr3) +/* + * Load the pae pdptrs. Return true is they are all valid. + */ +static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) { gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; - unsigned offset = (cr3 & (PAGE_SIZE-1)) >> 5; + unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; int i; u64 pdpte; u64 *pdpt; + int ret; struct kvm_memory_slot *memslot; spin_lock(&vcpu->kvm->lock); @@ -304,16 +319,23 @@ static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu, /* FIXME: !memslot - emulate? 0xff? */ pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0); + ret = 1; for (i = 0; i < 4; ++i) { pdpte = pdpt[offset + i]; - if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) - break; + if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) { + ret = 0; + goto out; + } } + for (i = 0; i < 4; ++i) + vcpu->pdptrs[i] = pdpt[offset + i]; + +out: kunmap_atomic(pdpt, KM_USER0); spin_unlock(&vcpu->kvm->lock); - return i != 4; + return ret; } void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) @@ -359,8 +381,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } } else #endif - if (is_pae(vcpu) && - pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) { + if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->cr3)) { printk(KERN_DEBUG "set_cr0: #GP, pdptrs " "reserved bits\n"); inject_gp(vcpu); @@ -381,6 +402,7 @@ EXPORT_SYMBOL_GPL(set_cr0); void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) { + kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f)); } EXPORT_SYMBOL_GPL(lmsw); @@ -393,7 +415,7 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return; } - if (kvm_arch_ops->is_long_mode(vcpu)) { + if (is_long_mode(vcpu)) { if (!(cr4 & CR4_PAE_MASK)) { printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " "in long mode\n"); @@ -401,7 +423,7 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return; } } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK) - && pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) { + && !load_pdptrs(vcpu, vcpu->cr3)) { printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); inject_gp(vcpu); } @@ -420,7 +442,7 @@ EXPORT_SYMBOL_GPL(set_cr4); void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) { - if (kvm_arch_ops->is_long_mode(vcpu)) { + if (is_long_mode(vcpu)) { if ( cr3 & CR3_L_MODE_RESEVED_BITS) { printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); inject_gp(vcpu); @@ -433,7 +455,7 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) return; } if (is_paging(vcpu) && is_pae(vcpu) && - pdptrs_have_reserved_bits_set(vcpu, cr3)) { + !load_pdptrs(vcpu, cr3)) { printk(KERN_DEBUG "set_cr3: #GP, pdptrs " "reserved bits\n"); inject_gp(vcpu); @@ -443,7 +465,19 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) vcpu->cr3 = cr3; spin_lock(&vcpu->kvm->lock); - vcpu->mmu.new_cr3(vcpu); + /* + * Does the new cr3 value map to physical memory? (Note, we + * catch an invalid cr3 even in real-mode, because it would + * cause trouble later on when we turn on paging anyway.) + * + * A real CPU would silently accept an invalid cr3 and would + * attempt to use it - with largely undefined (and often hard + * to debug) behavior on the guest side. + */ + if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) + inject_gp(vcpu); + else + vcpu->mmu.new_cr3(vcpu); spin_unlock(&vcpu->kvm->lock); } EXPORT_SYMBOL_GPL(set_cr3); @@ -494,7 +528,7 @@ static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n) struct kvm_vcpu *vcpu; r = -EINVAL; - if (n < 0 || n >= KVM_MAX_VCPUS) + if (!valid_vcpu(n)) goto out; vcpu = &kvm->vcpus[n]; @@ -511,17 +545,18 @@ static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n) vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; vcpu->cpu = -1; /* First load will set up TR */ - vcpu->kvm = kvm; r = kvm_arch_ops->vcpu_create(vcpu); if (r < 0) goto out_free_vcpus; - kvm_arch_ops->vcpu_load(vcpu); + r = kvm_mmu_create(vcpu); + if (r < 0) + goto out_free_vcpus; - r = kvm_arch_ops->vcpu_setup(vcpu); + kvm_arch_ops->vcpu_load(vcpu); + r = kvm_mmu_setup(vcpu); if (r >= 0) - r = kvm_mmu_init(vcpu); - + r = kvm_arch_ops->vcpu_setup(vcpu); vcpu_put(vcpu); if (r < 0) @@ -626,6 +661,7 @@ raced: | __GFP_ZERO); if (!new.phys_mem[i]) goto out_free; + new.phys_mem[i]->private = 0; } } @@ -680,6 +716,13 @@ out: return r; } +static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot) +{ + spin_lock(&vcpu->kvm->lock); + kvm_mmu_slot_remove_write_access(vcpu, slot); + spin_unlock(&vcpu->kvm->lock); +} + /* * Get (and clear) the dirty memory log for a memory slot. */ @@ -689,6 +732,7 @@ static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot; int r, i; int n; + int cleared; unsigned long any = 0; spin_lock(&kvm->lock); @@ -719,15 +763,17 @@ static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm, if (any) { - spin_lock(&kvm->lock); - kvm_mmu_slot_remove_write_access(kvm, log->slot); - spin_unlock(&kvm->lock); - memset(memslot->dirty_bitmap, 0, n); + cleared = 0; for (i = 0; i < KVM_MAX_VCPUS; ++i) { struct kvm_vcpu *vcpu = vcpu_load(kvm, i); if (!vcpu) continue; + if (!cleared) { + do_remove_write_access(vcpu, log->slot); + memset(memslot->dirty_bitmap, 0, n); + cleared = 1; + } kvm_arch_ops->tlb_flush(vcpu); vcpu_put(vcpu); } @@ -855,6 +901,27 @@ static int emulator_read_emulated(unsigned long addr, } } +static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, + unsigned long val, int bytes) +{ + struct kvm_memory_slot *m; + struct page *page; + void *virt; + + if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT)) + return 0; + m = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT); + if (!m) + return 0; + page = gfn_to_page(m, gpa >> PAGE_SHIFT); + kvm_mmu_pre_write(vcpu, gpa, bytes); + virt = kmap_atomic(page, KM_USER0); + memcpy(virt + offset_in_page(gpa), &val, bytes); + kunmap_atomic(virt, KM_USER0); + kvm_mmu_post_write(vcpu, gpa, bytes); + return 1; +} + static int emulator_write_emulated(unsigned long addr, unsigned long val, unsigned int bytes, @@ -866,6 +933,9 @@ static int emulator_write_emulated(unsigned long addr, if (gpa == UNMAPPED_GVA) return X86EMUL_PROPAGATE_FAULT; + if (emulator_write_phys(vcpu, gpa, val, bytes)) + return X86EMUL_CONTINUE; + vcpu->mmio_needed = 1; vcpu->mmio_phys_addr = gpa; vcpu->mmio_size = bytes; @@ -890,6 +960,30 @@ static int emulator_cmpxchg_emulated(unsigned long addr, return emulator_write_emulated(addr, new, bytes, ctxt); } +#ifdef CONFIG_X86_32 + +static int emulator_cmpxchg8b_emulated(unsigned long addr, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi, + struct x86_emulate_ctxt *ctxt) +{ + static int reported; + int r; + + if (!reported) { + reported = 1; + printk(KERN_WARNING "kvm: emulating exchange8b as write\n"); + } + r = emulator_write_emulated(addr, new_lo, 4, ctxt); + if (r != X86EMUL_CONTINUE) + return r; + return emulator_write_emulated(addr+4, new_hi, 4, ctxt); +} + +#endif + static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) { return kvm_arch_ops->get_segment_base(vcpu, seg); @@ -897,18 +991,15 @@ static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) { - spin_lock(&vcpu->kvm->lock); - vcpu->mmu.inval_page(vcpu, address); - spin_unlock(&vcpu->kvm->lock); - kvm_arch_ops->invlpg(vcpu, address); return X86EMUL_CONTINUE; } int emulate_clts(struct kvm_vcpu *vcpu) { - unsigned long cr0 = vcpu->cr0; + unsigned long cr0; - cr0 &= ~CR0_TS_MASK; + kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); + cr0 = vcpu->cr0 & ~CR0_TS_MASK; kvm_arch_ops->set_cr0(vcpu, cr0); return X86EMUL_CONTINUE; } @@ -967,6 +1058,9 @@ struct x86_emulate_ops emulate_ops = { .read_emulated = emulator_read_emulated, .write_emulated = emulator_write_emulated, .cmpxchg_emulated = emulator_cmpxchg_emulated, +#ifdef CONFIG_X86_32 + .cmpxchg8b_emulated = emulator_cmpxchg8b_emulated, +#endif }; int emulate_instruction(struct kvm_vcpu *vcpu, @@ -1016,6 +1110,8 @@ int emulate_instruction(struct kvm_vcpu *vcpu, } if (r) { + if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) + return EMULATE_DONE; if (!vcpu->mmio_needed) { report_emulation_failure(&emulate_ctxt); return EMULATE_FAIL; @@ -1061,6 +1157,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) { + kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); switch (cr) { case 0: return vcpu->cr0; @@ -1098,6 +1195,54 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, } } +int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) +{ + u64 data; + + switch (msr) { + case 0xc0010010: /* SYSCFG */ + case 0xc0010015: /* HWCR */ + case MSR_IA32_PLATFORM_ID: + case MSR_IA32_P5_MC_ADDR: + case MSR_IA32_P5_MC_TYPE: + case MSR_IA32_MC0_CTL: + case MSR_IA32_MCG_STATUS: + case MSR_IA32_MCG_CAP: + case MSR_IA32_MC0_MISC: + case MSR_IA32_MC0_MISC+4: + case MSR_IA32_MC0_MISC+8: + case MSR_IA32_MC0_MISC+12: + case MSR_IA32_MC0_MISC+16: + case MSR_IA32_UCODE_REV: + case MSR_IA32_PERF_STATUS: + /* MTRR registers */ + case 0xfe: + case 0x200 ... 0x2ff: + data = 0; + break; + case 0xcd: /* fsb frequency */ + data = 3; + break; + case MSR_IA32_APICBASE: + data = vcpu->apic_base; + break; + case MSR_IA32_MISC_ENABLE: + data = vcpu->ia32_misc_enable_msr; + break; +#ifdef CONFIG_X86_64 + case MSR_EFER: + data = vcpu->shadow_efer; + break; +#endif + default: + printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr); + return 1; + } + *pdata = data; + return 0; +} +EXPORT_SYMBOL_GPL(kvm_get_msr_common); + /* * Reads an msr value (of 'msr_index') into 'pdata'. * Returns 0 on success, non-0 otherwise. @@ -1110,7 +1255,7 @@ static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) #ifdef CONFIG_X86_64 -void set_efer(struct kvm_vcpu *vcpu, u64 efer) +static void set_efer(struct kvm_vcpu *vcpu, u64 efer) { if (efer & EFER_RESERVED_BITS) { printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", @@ -1133,10 +1278,39 @@ void set_efer(struct kvm_vcpu *vcpu, u64 efer) vcpu->shadow_efer = efer; } -EXPORT_SYMBOL_GPL(set_efer); #endif +int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) +{ + switch (msr) { +#ifdef CONFIG_X86_64 + case MSR_EFER: + set_efer(vcpu, data); + break; +#endif + case MSR_IA32_MC0_STATUS: + printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", + __FUNCTION__, data); + break; + case MSR_IA32_UCODE_REV: + case MSR_IA32_UCODE_WRITE: + case 0x200 ... 0x2ff: /* MTRRs */ + break; + case MSR_IA32_APICBASE: + vcpu->apic_base = data; + break; + case MSR_IA32_MISC_ENABLE: + vcpu->ia32_misc_enable_msr = data; + break; + default: + printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr); + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_set_msr_common); + /* * Writes msr value into into the appropriate "register". * Returns 0 on success, non-0 otherwise. @@ -1179,7 +1353,7 @@ static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run) struct kvm_vcpu *vcpu; int r; - if (kvm_run->vcpu < 0 || kvm_run->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(kvm_run->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, kvm_run->vcpu); @@ -1208,7 +1382,7 @@ static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs) { struct kvm_vcpu *vcpu; - if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(regs->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, regs->vcpu); @@ -1254,7 +1428,7 @@ static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs) { struct kvm_vcpu *vcpu; - if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(regs->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, regs->vcpu); @@ -1301,7 +1475,7 @@ static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs) struct kvm_vcpu *vcpu; struct descriptor_table dt; - if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(sregs->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, sregs->vcpu); if (!vcpu) @@ -1324,6 +1498,7 @@ static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs) sregs->gdt.limit = dt.limit; sregs->gdt.base = dt.base; + kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); sregs->cr0 = vcpu->cr0; sregs->cr2 = vcpu->cr2; sregs->cr3 = vcpu->cr3; @@ -1353,7 +1528,7 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs) int i; struct descriptor_table dt; - if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(sregs->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, sregs->vcpu); if (!vcpu) @@ -1388,11 +1563,15 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs) #endif vcpu->apic_base = sregs->apic_base; + kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); + mmu_reset_needed |= vcpu->cr0 != sregs->cr0; kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0); mmu_reset_needed |= vcpu->cr4 != sregs->cr4; kvm_arch_ops->set_cr4(vcpu, sregs->cr4); + if (!is_long_mode(vcpu) && is_pae(vcpu)) + load_pdptrs(vcpu, vcpu->cr3); if (mmu_reset_needed) kvm_mmu_reset_context(vcpu); @@ -1412,6 +1591,9 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs) /* * List of msr numbers which we expose to userspace through KVM_GET_MSRS * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. + * + * This list is modified at module load time to reflect the + * capabilities of the host cpu. */ static u32 msrs_to_save[] = { MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, @@ -1422,6 +1604,26 @@ static u32 msrs_to_save[] = { MSR_IA32_TIME_STAMP_COUNTER, }; +static unsigned num_msrs_to_save; + +static u32 emulated_msrs[] = { + MSR_IA32_MISC_ENABLE, +}; + +static __init void kvm_init_msr_list(void) +{ + u32 dummy[2]; + unsigned i, j; + + for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) { + if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0) + continue; + if (j < i) + msrs_to_save[j] = msrs_to_save[i]; + j++; + } + num_msrs_to_save = j; +} /* * Adapt set_msr() to msr_io()'s calling convention @@ -1444,7 +1646,7 @@ static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs, struct kvm_vcpu *vcpu; int i; - if (msrs->vcpu < 0 || msrs->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(msrs->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, msrs->vcpu); @@ -1537,7 +1739,7 @@ static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq) { struct kvm_vcpu *vcpu; - if (irq->vcpu < 0 || irq->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(irq->vcpu)) return -EINVAL; if (irq->irq < 0 || irq->irq >= 256) return -EINVAL; @@ -1559,7 +1761,7 @@ static int kvm_dev_ioctl_debug_guest(struct kvm *kvm, struct kvm_vcpu *vcpu; int r; - if (dbg->vcpu < 0 || dbg->vcpu >= KVM_MAX_VCPUS) + if (!valid_vcpu(dbg->vcpu)) return -EINVAL; vcpu = vcpu_load(kvm, dbg->vcpu); if (!vcpu) @@ -1579,6 +1781,9 @@ static long kvm_dev_ioctl(struct file *filp, int r = -EINVAL; switch (ioctl) { + case KVM_GET_API_VERSION: + r = KVM_API_VERSION; + break; case KVM_CREATE_VCPU: { r = kvm_dev_ioctl_create_vcpu(kvm, arg); if (r) @@ -1592,12 +1797,12 @@ static long kvm_dev_ioctl(struct file *filp, if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run)) goto out; r = kvm_dev_ioctl_run(kvm, &kvm_run); - if (r < 0) + if (r < 0 && r != -EINTR) goto out; - r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) + if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) { + r = -EFAULT; goto out; - r = 0; + } break; } case KVM_GET_REGS: { @@ -1730,17 +1935,23 @@ static long kvm_dev_ioctl(struct file *filp, if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) goto out; n = msr_list.nmsrs; - msr_list.nmsrs = ARRAY_SIZE(msrs_to_save); + msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs); if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) goto out; r = -E2BIG; - if (n < ARRAY_SIZE(msrs_to_save)) + if (n < num_msrs_to_save) goto out; r = -EFAULT; if (copy_to_user(user_msr_list->indices, &msrs_to_save, - sizeof msrs_to_save)) + num_msrs_to_save * sizeof(u32))) + goto out; + if (copy_to_user(user_msr_list->indices + + num_msrs_to_save * sizeof(u32), + &emulated_msrs, + ARRAY_SIZE(emulated_msrs) * sizeof(u32))) goto out; r = 0; + break; } default: ; @@ -1838,17 +2049,22 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) { int r; - kvm_arch_ops = ops; + if (kvm_arch_ops) { + printk(KERN_ERR "kvm: already loaded the other module\n"); + return -EEXIST; + } - if (!kvm_arch_ops->cpu_has_kvm_support()) { + if (!ops->cpu_has_kvm_support()) { printk(KERN_ERR "kvm: no hardware support\n"); return -EOPNOTSUPP; } - if (kvm_arch_ops->disabled_by_bios()) { + if (ops->disabled_by_bios()) { printk(KERN_ERR "kvm: disabled by bios\n"); return -EOPNOTSUPP; } + kvm_arch_ops = ops; + r = kvm_arch_ops->hardware_setup(); if (r < 0) return r; @@ -1880,6 +2096,7 @@ void kvm_exit_arch(void) unregister_reboot_notifier(&kvm_reboot_notifier); on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); kvm_arch_ops->hardware_unsetup(); + kvm_arch_ops = NULL; } static __init int kvm_init(void) @@ -1889,6 +2106,8 @@ static __init int kvm_init(void) kvm_init_debug(); + kvm_init_msr_list(); + if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) { r = -ENOMEM; goto out; diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 3d367cbfe1f..22c426cd8cb 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -26,7 +26,31 @@ #include "vmx.h" #include "kvm.h" +#undef MMU_DEBUG + +#undef AUDIT + +#ifdef AUDIT +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg); +#else +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} +#endif + +#ifdef MMU_DEBUG + +#define pgprintk(x...) do { if (dbg) printk(x); } while (0) +#define rmap_printk(x...) do { if (dbg) printk(x); } while (0) + +#else + #define pgprintk(x...) do { } while (0) +#define rmap_printk(x...) do { } while (0) + +#endif + +#if defined(MMU_DEBUG) || defined(AUDIT) +static int dbg = 1; +#endif #define ASSERT(x) \ if (!(x)) { \ @@ -34,8 +58,10 @@ __FILE__, __LINE__, #x); \ } -#define PT64_ENT_PER_PAGE 512 -#define PT32_ENT_PER_PAGE 1024 +#define PT64_PT_BITS 9 +#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS) +#define PT32_PT_BITS 10 +#define PT32_ENT_PER_PAGE (1 << PT32_PT_BITS) #define PT_WRITABLE_SHIFT 1 @@ -117,6 +143,7 @@ #define PFERR_PRESENT_MASK (1U << 0) #define PFERR_WRITE_MASK (1U << 1) #define PFERR_USER_MASK (1U << 2) +#define PFERR_FETCH_MASK (1U << 4) #define PT64_ROOT_LEVEL 4 #define PT32_ROOT_LEVEL 2 @@ -125,6 +152,13 @@ #define PT_DIRECTORY_LEVEL 2 #define PT_PAGE_TABLE_LEVEL 1 +#define RMAP_EXT 4 + +struct kvm_rmap_desc { + u64 *shadow_ptes[RMAP_EXT]; + struct kvm_rmap_desc *more; +}; + static int is_write_protection(struct kvm_vcpu *vcpu) { return vcpu->cr0 & CR0_WP_MASK; @@ -135,6 +169,11 @@ static int is_cpuid_PSE36(void) return 1; } +static int is_nx(struct kvm_vcpu *vcpu) +{ + return vcpu->shadow_efer & EFER_NX; +} + static int is_present_pte(unsigned long pte) { return pte & PT_PRESENT_MASK; @@ -150,32 +189,272 @@ static int is_io_pte(unsigned long pte) return pte & PT_SHADOW_IO_MARK; } +static int is_rmap_pte(u64 pte) +{ + return (pte & (PT_WRITABLE_MASK | PT_PRESENT_MASK)) + == (PT_WRITABLE_MASK | PT_PRESENT_MASK); +} + +static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, + size_t objsize, int min) +{ + void *obj; + + if (cache->nobjs >= min) + return 0; + while (cache->nobjs < ARRAY_SIZE(cache->objects)) { + obj = kzalloc(objsize, GFP_NOWAIT); + if (!obj) + return -ENOMEM; + cache->objects[cache->nobjs++] = obj; + } + return 0; +} + +static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) +{ + while (mc->nobjs) + kfree(mc->objects[--mc->nobjs]); +} + +static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) +{ + int r; + + r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache, + sizeof(struct kvm_pte_chain), 4); + if (r) + goto out; + r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache, + sizeof(struct kvm_rmap_desc), 1); +out: + return r; +} + +static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) +{ + mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache); + mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache); +} + +static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc, + size_t size) +{ + void *p; + + BUG_ON(!mc->nobjs); + p = mc->objects[--mc->nobjs]; + memset(p, 0, size); + return p; +} + +static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj) +{ + if (mc->nobjs < KVM_NR_MEM_OBJS) + mc->objects[mc->nobjs++] = obj; + else + kfree(obj); +} + +static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu) +{ + return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache, + sizeof(struct kvm_pte_chain)); +} + +static void mmu_free_pte_chain(struct kvm_vcpu *vcpu, + struct kvm_pte_chain *pc) +{ + mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc); +} + +static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu) +{ + return mmu_memory_cache_alloc(&vcpu->mmu_rmap_desc_cache, + sizeof(struct kvm_rmap_desc)); +} + +static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu, + struct kvm_rmap_desc *rd) +{ + mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd); +} + +/* + * Reverse mapping data structures: + * + * If page->private bit zero is zero, then page->private points to the + * shadow page table entry that points to page_address(page). + * + * If page->private bit zero is one, (then page->private & ~1) points + * to a struct kvm_rmap_desc containing more mappings. + */ +static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte) +{ + struct page *page; + struct kvm_rmap_desc *desc; + int i; + + if (!is_rmap_pte(*spte)) + return; + page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); + if (!page->private) { + rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); + page->private = (unsigned long)spte; + } else if (!(page->private & 1)) { + rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); + desc = mmu_alloc_rmap_desc(vcpu); + desc->shadow_ptes[0] = (u64 *)page->private; + desc->shadow_ptes[1] = spte; + page->private = (unsigned long)desc | 1; + } else { + rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); + desc = (struct kvm_rmap_desc *)(page->private & ~1ul); + while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) + desc = desc->more; + if (desc->shadow_ptes[RMAP_EXT-1]) { + desc->more = mmu_alloc_rmap_desc(vcpu); + desc = desc->more; + } + for (i = 0; desc->shadow_ptes[i]; ++i) + ; + desc->shadow_ptes[i] = spte; + } +} + +static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu, + struct page *page, + struct kvm_rmap_desc *desc, + int i, + struct kvm_rmap_desc *prev_desc) +{ + int j; + + for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j) + ; + desc->shadow_ptes[i] = desc->shadow_ptes[j]; + desc->shadow_ptes[j] = 0; + if (j != 0) + return; + if (!prev_desc && !desc->more) + page->private = (unsigned long)desc->shadow_ptes[0]; + else + if (prev_desc) + prev_desc->more = desc->more; + else + page->private = (unsigned long)desc->more | 1; + mmu_free_rmap_desc(vcpu, desc); +} + +static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte) +{ + struct page *page; + struct kvm_rmap_desc *desc; + struct kvm_rmap_desc *prev_desc; + int i; + + if (!is_rmap_pte(*spte)) + return; + page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); + if (!page->private) { + printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); + BUG(); + } else if (!(page->private & 1)) { + rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte); + if ((u64 *)page->private != spte) { + printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n", + spte, *spte); + BUG(); + } + page->private = 0; + } else { + rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte); + desc = (struct kvm_rmap_desc *)(page->private & ~1ul); + prev_desc = NULL; + while (desc) { + for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) + if (desc->shadow_ptes[i] == spte) { + rmap_desc_remove_entry(vcpu, page, + desc, i, + prev_desc); + return; + } + prev_desc = desc; + desc = desc->more; + } + BUG(); + } +} + +static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) +{ + struct kvm *kvm = vcpu->kvm; + struct page *page; + struct kvm_memory_slot *slot; + struct kvm_rmap_desc *desc; + u64 *spte; + + slot = gfn_to_memslot(kvm, gfn); + BUG_ON(!slot); + page = gfn_to_page(slot, gfn); + + while (page->private) { + if (!(page->private & 1)) + spte = (u64 *)page->private; + else { + desc = (struct kvm_rmap_desc *)(page->private & ~1ul); + spte = desc->shadow_ptes[0]; + } + BUG_ON(!spte); + BUG_ON((*spte & PT64_BASE_ADDR_MASK) != + page_to_pfn(page) << PAGE_SHIFT); + BUG_ON(!(*spte & PT_PRESENT_MASK)); + BUG_ON(!(*spte & PT_WRITABLE_MASK)); + rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); + rmap_remove(vcpu, spte); + kvm_arch_ops->tlb_flush(vcpu); + *spte &= ~(u64)PT_WRITABLE_MASK; + } +} + +static int is_empty_shadow_page(hpa_t page_hpa) +{ + u64 *pos; + u64 *end; + + for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u64); + pos != end; pos++) + if (*pos != 0) { + printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__, + pos, *pos); + return 0; + } + return 1; +} + static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa) { struct kvm_mmu_page *page_head = page_header(page_hpa); + ASSERT(is_empty_shadow_page(page_hpa)); list_del(&page_head->link); page_head->page_hpa = page_hpa; list_add(&page_head->link, &vcpu->free_pages); + ++vcpu->kvm->n_free_mmu_pages; } -static int is_empty_shadow_page(hpa_t page_hpa) +static unsigned kvm_page_table_hashfn(gfn_t gfn) { - u32 *pos; - u32 *end; - for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u32); - pos != end; pos++) - if (*pos != 0) - return 0; - return 1; + return gfn; } -static hpa_t kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, u64 *parent_pte) +static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, + u64 *parent_pte) { struct kvm_mmu_page *page; if (list_empty(&vcpu->free_pages)) - return INVALID_PAGE; + return NULL; page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link); list_del(&page->link); @@ -183,8 +462,239 @@ static hpa_t kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, u64 *parent_pte) ASSERT(is_empty_shadow_page(page->page_hpa)); page->slot_bitmap = 0; page->global = 1; + page->multimapped = 0; page->parent_pte = parent_pte; - return page->page_hpa; + --vcpu->kvm->n_free_mmu_pages; + return page; +} + +static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page, u64 *parent_pte) +{ + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + int i; + + if (!parent_pte) + return; + if (!page->multimapped) { + u64 *old = page->parent_pte; + + if (!old) { + page->parent_pte = parent_pte; + return; + } + page->multimapped = 1; + pte_chain = mmu_alloc_pte_chain(vcpu); + INIT_HLIST_HEAD(&page->parent_ptes); + hlist_add_head(&pte_chain->link, &page->parent_ptes); + pte_chain->parent_ptes[0] = old; + } + hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link) { + if (pte_chain->parent_ptes[NR_PTE_CHAIN_ENTRIES-1]) + continue; + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) + if (!pte_chain->parent_ptes[i]) { + pte_chain->parent_ptes[i] = parent_pte; + return; + } + } + pte_chain = mmu_alloc_pte_chain(vcpu); + BUG_ON(!pte_chain); + hlist_add_head(&pte_chain->link, &page->parent_ptes); + pte_chain->parent_ptes[0] = parent_pte; +} + +static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page, + u64 *parent_pte) +{ + struct kvm_pte_chain *pte_chain; + struct hlist_node *node; + int i; + + if (!page->multimapped) { + BUG_ON(page->parent_pte != parent_pte); + page->parent_pte = NULL; + return; + } + hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link) + for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) { + if (!pte_chain->parent_ptes[i]) + break; + if (pte_chain->parent_ptes[i] != parent_pte) + continue; + while (i + 1 < NR_PTE_CHAIN_ENTRIES + && pte_chain->parent_ptes[i + 1]) { + pte_chain->parent_ptes[i] + = pte_chain->parent_ptes[i + 1]; + ++i; + } + pte_chain->parent_ptes[i] = NULL; + if (i == 0) { + hlist_del(&pte_chain->link); + mmu_free_pte_chain(vcpu, pte_chain); + if (hlist_empty(&page->parent_ptes)) { + page->multimapped = 0; + page->parent_pte = NULL; + } + } + return; + } + BUG(); +} + +static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm_vcpu *vcpu, + gfn_t gfn) +{ + unsigned index; + struct hlist_head *bucket; + struct kvm_mmu_page *page; + struct hlist_node *node; + + pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); + index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; + bucket = &vcpu->kvm->mmu_page_hash[index]; + hlist_for_each_entry(page, node, bucket, hash_link) + if (page->gfn == gfn && !page->role.metaphysical) { + pgprintk("%s: found role %x\n", + __FUNCTION__, page->role.word); + return page; + } + return NULL; +} + +static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + gva_t gaddr, + unsigned level, + int metaphysical, + u64 *parent_pte) +{ + union kvm_mmu_page_role role; + unsigned index; + unsigned quadrant; + struct hlist_head *bucket; + struct kvm_mmu_page *page; + struct hlist_node *node; + + role.word = 0; + role.glevels = vcpu->mmu.root_level; + role.level = level; + role.metaphysical = metaphysical; + if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) { + quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); + quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; + role.quadrant = quadrant; + } + pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__, + gfn, role.word); + index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; + bucket = &vcpu->kvm->mmu_page_hash[index]; + hlist_for_each_entry(page, node, bucket, hash_link) + if (page->gfn == gfn && page->role.word == role.word) { + mmu_page_add_parent_pte(vcpu, page, parent_pte); + pgprintk("%s: found\n", __FUNCTION__); + return page; + } + page = kvm_mmu_alloc_page(vcpu, parent_pte); + if (!page) + return page; + pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word); + page->gfn = gfn; + page->role = role; + hlist_add_head(&page->hash_link, bucket); + if (!metaphysical) + rmap_write_protect(vcpu, gfn); + return page; +} + +static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page) +{ + unsigned i; + u64 *pt; + u64 ent; + + pt = __va(page->page_hpa); + + if (page->role.level == PT_PAGE_TABLE_LEVEL) { + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + if (pt[i] & PT_PRESENT_MASK) + rmap_remove(vcpu, &pt[i]); + pt[i] = 0; + } + kvm_arch_ops->tlb_flush(vcpu); + return; + } + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + ent = pt[i]; + + pt[i] = 0; + if (!(ent & PT_PRESENT_MASK)) + continue; + ent &= PT64_BASE_ADDR_MASK; + mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]); + } +} + +static void kvm_mmu_put_page(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page, + u64 *parent_pte) +{ + mmu_page_remove_parent_pte(vcpu, page, parent_pte); +} + +static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *page) +{ + u64 *parent_pte; + + while (page->multimapped || page->parent_pte) { + if (!page->multimapped) + parent_pte = page->parent_pte; + else { + struct kvm_pte_chain *chain; + + chain = container_of(page->parent_ptes.first, + struct kvm_pte_chain, link); + parent_pte = chain->parent_ptes[0]; + } + BUG_ON(!parent_pte); + kvm_mmu_put_page(vcpu, page, parent_pte); + *parent_pte = 0; + } + kvm_mmu_page_unlink_children(vcpu, page); + if (!page->root_count) { + hlist_del(&page->hash_link); + kvm_mmu_free_page(vcpu, page->page_hpa); + } else { + list_del(&page->link); + list_add(&page->link, &vcpu->kvm->active_mmu_pages); + } +} + +static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) +{ + unsigned index; + struct hlist_head *bucket; + struct kvm_mmu_page *page; + struct hlist_node *node, *n; + int r; + + pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); + r = 0; + index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; + bucket = &vcpu->kvm->mmu_page_hash[index]; + hlist_for_each_entry_safe(page, node, n, bucket, hash_link) + if (page->gfn == gfn && !page->role.metaphysical) { + pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn, + page->role.word); + kvm_mmu_zap_page(vcpu, page); + r = 1; + } + return r; } static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa) @@ -225,35 +735,6 @@ hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva) return gpa_to_hpa(vcpu, gpa); } - -static void release_pt_page_64(struct kvm_vcpu *vcpu, hpa_t page_hpa, - int level) -{ - ASSERT(vcpu); - ASSERT(VALID_PAGE(page_hpa)); - ASSERT(level <= PT64_ROOT_LEVEL && level > 0); - - if (level == 1) - memset(__va(page_hpa), 0, PAGE_SIZE); - else { - u64 *pos; - u64 *end; - - for (pos = __va(page_hpa), end = pos + PT64_ENT_PER_PAGE; - pos != end; pos++) { - u64 current_ent = *pos; - - *pos = 0; - if (is_present_pte(current_ent)) - release_pt_page_64(vcpu, - current_ent & - PT64_BASE_ADDR_MASK, - level - 1); - } - } - kvm_mmu_free_page(vcpu, page_hpa); -} - static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) { } @@ -266,52 +747,109 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p) for (; ; level--) { u32 index = PT64_INDEX(v, level); u64 *table; + u64 pte; ASSERT(VALID_PAGE(table_addr)); table = __va(table_addr); if (level == 1) { + pte = table[index]; + if (is_present_pte(pte) && is_writeble_pte(pte)) + return 0; mark_page_dirty(vcpu->kvm, v >> PAGE_SHIFT); page_header_update_slot(vcpu->kvm, table, v); table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; + rmap_add(vcpu, &table[index]); return 0; } if (table[index] == 0) { - hpa_t new_table = kvm_mmu_alloc_page(vcpu, - &table[index]); - - if (!VALID_PAGE(new_table)) { + struct kvm_mmu_page *new_table; + gfn_t pseudo_gfn; + + pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK) + >> PAGE_SHIFT; + new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, + v, level - 1, + 1, &table[index]); + if (!new_table) { pgprintk("nonpaging_map: ENOMEM\n"); return -ENOMEM; } - if (level == PT32E_ROOT_LEVEL) - table[index] = new_table | PT_PRESENT_MASK; - else - table[index] = new_table | PT_PRESENT_MASK | - PT_WRITABLE_MASK | PT_USER_MASK; + table[index] = new_table->page_hpa | PT_PRESENT_MASK + | PT_WRITABLE_MASK | PT_USER_MASK; } table_addr = table[index] & PT64_BASE_ADDR_MASK; } } -static void nonpaging_flush(struct kvm_vcpu *vcpu) +static void mmu_free_roots(struct kvm_vcpu *vcpu) { - hpa_t root = vcpu->mmu.root_hpa; + int i; + struct kvm_mmu_page *page; - ++kvm_stat.tlb_flush; - pgprintk("nonpaging_flush\n"); - ASSERT(VALID_PAGE(root)); - release_pt_page_64(vcpu, root, vcpu->mmu.shadow_root_level); - root = kvm_mmu_alloc_page(vcpu, NULL); - ASSERT(VALID_PAGE(root)); - vcpu->mmu.root_hpa = root; - if (is_paging(vcpu)) - root |= (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)); - kvm_arch_ops->set_cr3(vcpu, root); - kvm_arch_ops->tlb_flush(vcpu); +#ifdef CONFIG_X86_64 + if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) { + hpa_t root = vcpu->mmu.root_hpa; + + ASSERT(VALID_PAGE(root)); + page = page_header(root); + --page->root_count; + vcpu->mmu.root_hpa = INVALID_PAGE; + return; + } +#endif + for (i = 0; i < 4; ++i) { + hpa_t root = vcpu->mmu.pae_root[i]; + + ASSERT(VALID_PAGE(root)); + root &= PT64_BASE_ADDR_MASK; + page = page_header(root); + --page->root_count; + vcpu->mmu.pae_root[i] = INVALID_PAGE; + } + vcpu->mmu.root_hpa = INVALID_PAGE; +} + +static void mmu_alloc_roots(struct kvm_vcpu *vcpu) +{ + int i; + gfn_t root_gfn; + struct kvm_mmu_page *page; + + root_gfn = vcpu->cr3 >> PAGE_SHIFT; + +#ifdef CONFIG_X86_64 + if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) { + hpa_t root = vcpu->mmu.root_hpa; + + ASSERT(!VALID_PAGE(root)); + page = kvm_mmu_get_page(vcpu, root_gfn, 0, + PT64_ROOT_LEVEL, 0, NULL); + root = page->page_hpa; + ++page->root_count; + vcpu->mmu.root_hpa = root; + return; + } +#endif + for (i = 0; i < 4; ++i) { + hpa_t root = vcpu->mmu.pae_root[i]; + + ASSERT(!VALID_PAGE(root)); + if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) + root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT; + else if (vcpu->mmu.root_level == 0) + root_gfn = 0; + page = kvm_mmu_get_page(vcpu, root_gfn, i << 30, + PT32_ROOT_LEVEL, !is_paging(vcpu), + NULL); + root = page->page_hpa; + ++page->root_count; + vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; + } + vcpu->mmu.root_hpa = __pa(vcpu->mmu.pae_root); } static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) @@ -322,43 +860,29 @@ static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code) { - int ret; gpa_t addr = gva; + hpa_t paddr; + int r; + + r = mmu_topup_memory_caches(vcpu); + if (r) + return r; ASSERT(vcpu); ASSERT(VALID_PAGE(vcpu->mmu.root_hpa)); - for (;;) { - hpa_t paddr; - - paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK); - if (is_error_hpa(paddr)) - return 1; + paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK); - ret = nonpaging_map(vcpu, addr & PAGE_MASK, paddr); - if (ret) { - nonpaging_flush(vcpu); - continue; - } - break; - } - return ret; -} + if (is_error_hpa(paddr)) + return 1; -static void nonpaging_inval_page(struct kvm_vcpu *vcpu, gva_t addr) -{ + return nonpaging_map(vcpu, addr & PAGE_MASK, paddr); } static void nonpaging_free(struct kvm_vcpu *vcpu) { - hpa_t root; - - ASSERT(vcpu); - root = vcpu->mmu.root_hpa; - if (VALID_PAGE(root)) - release_pt_page_64(vcpu, root, vcpu->mmu.shadow_root_level); - vcpu->mmu.root_hpa = INVALID_PAGE; + mmu_free_roots(vcpu); } static int nonpaging_init_context(struct kvm_vcpu *vcpu) @@ -367,40 +891,31 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu) context->new_cr3 = nonpaging_new_cr3; context->page_fault = nonpaging_page_fault; - context->inval_page = nonpaging_inval_page; context->gva_to_gpa = nonpaging_gva_to_gpa; context->free = nonpaging_free; - context->root_level = PT32E_ROOT_LEVEL; + context->root_level = 0; context->shadow_root_level = PT32E_ROOT_LEVEL; - context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL); + mmu_alloc_roots(vcpu); ASSERT(VALID_PAGE(context->root_hpa)); kvm_arch_ops->set_cr3(vcpu, context->root_hpa); return 0; } - static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) { - struct kvm_mmu_page *page, *npage; - - list_for_each_entry_safe(page, npage, &vcpu->kvm->active_mmu_pages, - link) { - if (page->global) - continue; - - if (!page->parent_pte) - continue; - - *page->parent_pte = 0; - release_pt_page_64(vcpu, page->page_hpa, 1); - } ++kvm_stat.tlb_flush; kvm_arch_ops->tlb_flush(vcpu); } static void paging_new_cr3(struct kvm_vcpu *vcpu) { + pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3); + mmu_free_roots(vcpu); + if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) + kvm_mmu_free_some_pages(vcpu); + mmu_alloc_roots(vcpu); kvm_mmu_flush_tlb(vcpu); + kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); } static void mark_pagetable_nonglobal(void *shadow_pte) @@ -412,7 +927,8 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu, u64 *shadow_pte, gpa_t gaddr, int dirty, - u64 access_bits) + u64 access_bits, + gfn_t gfn) { hpa_t paddr; @@ -420,13 +936,10 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu, if (!dirty) access_bits &= ~PT_WRITABLE_MASK; - if (access_bits & PT_WRITABLE_MASK) - mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); + paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK); *shadow_pte |= access_bits; - paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK); - if (!(*shadow_pte & PT_GLOBAL_MASK)) mark_pagetable_nonglobal(shadow_pte); @@ -434,10 +947,31 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu, *shadow_pte |= gaddr; *shadow_pte |= PT_SHADOW_IO_MARK; *shadow_pte &= ~PT_PRESENT_MASK; - } else { - *shadow_pte |= paddr; - page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); + return; } + + *shadow_pte |= paddr; + + if (access_bits & PT_WRITABLE_MASK) { + struct kvm_mmu_page *shadow; + + shadow = kvm_mmu_lookup_page(vcpu, gfn); + if (shadow) { + pgprintk("%s: found shadow page for %lx, marking ro\n", + __FUNCTION__, gfn); + access_bits &= ~PT_WRITABLE_MASK; + if (is_writeble_pte(*shadow_pte)) { + *shadow_pte &= ~PT_WRITABLE_MASK; + kvm_arch_ops->tlb_flush(vcpu); + } + } + } + + if (access_bits & PT_WRITABLE_MASK) + mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); + + page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); + rmap_add(vcpu, shadow_pte); } static void inject_page_fault(struct kvm_vcpu *vcpu, @@ -464,51 +998,6 @@ static inline int fix_read_pf(u64 *shadow_ent) return 0; } -static int may_access(u64 pte, int write, int user) -{ - - if (user && !(pte & PT_USER_MASK)) - return 0; - if (write && !(pte & PT_WRITABLE_MASK)) - return 0; - return 1; -} - -/* - * Remove a shadow pte. - */ -static void paging_inval_page(struct kvm_vcpu *vcpu, gva_t addr) -{ - hpa_t page_addr = vcpu->mmu.root_hpa; - int level = vcpu->mmu.shadow_root_level; - - ++kvm_stat.invlpg; - - for (; ; level--) { - u32 index = PT64_INDEX(addr, level); - u64 *table = __va(page_addr); - - if (level == PT_PAGE_TABLE_LEVEL ) { - table[index] = 0; - return; - } - - if (!is_present_pte(table[index])) - return; - - page_addr = table[index] & PT64_BASE_ADDR_MASK; - - if (level == PT_DIRECTORY_LEVEL && - (table[index] & PT_SHADOW_PS_MARK)) { - table[index] = 0; - release_pt_page_64(vcpu, page_addr, PT_PAGE_TABLE_LEVEL); - - kvm_arch_ops->tlb_flush(vcpu); - return; - } - } -} - static void paging_free(struct kvm_vcpu *vcpu) { nonpaging_free(vcpu); @@ -522,37 +1011,40 @@ static void paging_free(struct kvm_vcpu *vcpu) #include "paging_tmpl.h" #undef PTTYPE -static int paging64_init_context(struct kvm_vcpu *vcpu) +static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level) { struct kvm_mmu *context = &vcpu->mmu; ASSERT(is_pae(vcpu)); context->new_cr3 = paging_new_cr3; context->page_fault = paging64_page_fault; - context->inval_page = paging_inval_page; context->gva_to_gpa = paging64_gva_to_gpa; context->free = paging_free; - context->root_level = PT64_ROOT_LEVEL; - context->shadow_root_level = PT64_ROOT_LEVEL; - context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL); + context->root_level = level; + context->shadow_root_level = level; + mmu_alloc_roots(vcpu); ASSERT(VALID_PAGE(context->root_hpa)); kvm_arch_ops->set_cr3(vcpu, context->root_hpa | (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK))); return 0; } +static int paging64_init_context(struct kvm_vcpu *vcpu) +{ + return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL); +} + static int paging32_init_context(struct kvm_vcpu *vcpu) { struct kvm_mmu *context = &vcpu->mmu; context->new_cr3 = paging_new_cr3; context->page_fault = paging32_page_fault; - context->inval_page = paging_inval_page; context->gva_to_gpa = paging32_gva_to_gpa; context->free = paging_free; context->root_level = PT32_ROOT_LEVEL; context->shadow_root_level = PT32E_ROOT_LEVEL; - context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL); + mmu_alloc_roots(vcpu); ASSERT(VALID_PAGE(context->root_hpa)); kvm_arch_ops->set_cr3(vcpu, context->root_hpa | (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK))); @@ -561,14 +1053,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu) static int paging32E_init_context(struct kvm_vcpu *vcpu) { - int ret; - - if ((ret = paging64_init_context(vcpu))) - return ret; - - vcpu->mmu.root_level = PT32E_ROOT_LEVEL; - vcpu->mmu.shadow_root_level = PT32E_ROOT_LEVEL; - return 0; + return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); } static int init_kvm_mmu(struct kvm_vcpu *vcpu) @@ -578,7 +1063,7 @@ static int init_kvm_mmu(struct kvm_vcpu *vcpu) if (!is_paging(vcpu)) return nonpaging_init_context(vcpu); - else if (kvm_arch_ops->is_long_mode(vcpu)) + else if (is_long_mode(vcpu)) return paging64_init_context(vcpu); else if (is_pae(vcpu)) return paging32E_init_context(vcpu); @@ -597,41 +1082,161 @@ static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) { + int r; + destroy_kvm_mmu(vcpu); - return init_kvm_mmu(vcpu); + r = init_kvm_mmu(vcpu); + if (r < 0) + goto out; + r = mmu_topup_memory_caches(vcpu); +out: + return r; } -static void free_mmu_pages(struct kvm_vcpu *vcpu) +void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) { - while (!list_empty(&vcpu->free_pages)) { + gfn_t gfn = gpa >> PAGE_SHIFT; + struct kvm_mmu_page *page; + struct kvm_mmu_page *child; + struct hlist_node *node, *n; + struct hlist_head *bucket; + unsigned index; + u64 *spte; + u64 pte; + unsigned offset = offset_in_page(gpa); + unsigned pte_size; + unsigned page_offset; + unsigned misaligned; + int level; + int flooded = 0; + + pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); + if (gfn == vcpu->last_pt_write_gfn) { + ++vcpu->last_pt_write_count; + if (vcpu->last_pt_write_count >= 3) + flooded = 1; + } else { + vcpu->last_pt_write_gfn = gfn; + vcpu->last_pt_write_count = 1; + } + index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; + bucket = &vcpu->kvm->mmu_page_hash[index]; + hlist_for_each_entry_safe(page, node, n, bucket, hash_link) { + if (page->gfn != gfn || page->role.metaphysical) + continue; + pte_size = page->role.glevels == PT32_ROOT_LEVEL ? 4 : 8; + misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1); + if (misaligned || flooded) { + /* + * Misaligned accesses are too much trouble to fix + * up; also, they usually indicate a page is not used + * as a page table. + * + * If we're seeing too many writes to a page, + * it may no longer be a page table, or we may be + * forking, in which case it is better to unmap the + * page. + */ + pgprintk("misaligned: gpa %llx bytes %d role %x\n", + gpa, bytes, page->role.word); + kvm_mmu_zap_page(vcpu, page); + continue; + } + page_offset = offset; + level = page->role.level; + if (page->role.glevels == PT32_ROOT_LEVEL) { + page_offset <<= 1; /* 32->64 */ + page_offset &= ~PAGE_MASK; + } + spte = __va(page->page_hpa); + spte += page_offset / sizeof(*spte); + pte = *spte; + if (is_present_pte(pte)) { + if (level == PT_PAGE_TABLE_LEVEL) + rmap_remove(vcpu, spte); + else { + child = page_header(pte & PT64_BASE_ADDR_MASK); + mmu_page_remove_parent_pte(vcpu, child, spte); + } + } + *spte = 0; + } +} + +void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) +{ +} + +int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) +{ + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); + + return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT); +} + +void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) +{ + while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) { struct kvm_mmu_page *page; + page = container_of(vcpu->kvm->active_mmu_pages.prev, + struct kvm_mmu_page, link); + kvm_mmu_zap_page(vcpu, page); + } +} +EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages); + +static void free_mmu_pages(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *page; + + while (!list_empty(&vcpu->kvm->active_mmu_pages)) { + page = container_of(vcpu->kvm->active_mmu_pages.next, + struct kvm_mmu_page, link); + kvm_mmu_zap_page(vcpu, page); + } + while (!list_empty(&vcpu->free_pages)) { page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link); list_del(&page->link); __free_page(pfn_to_page(page->page_hpa >> PAGE_SHIFT)); page->page_hpa = INVALID_PAGE; } + free_page((unsigned long)vcpu->mmu.pae_root); } static int alloc_mmu_pages(struct kvm_vcpu *vcpu) { + struct page *page; int i; ASSERT(vcpu); for (i = 0; i < KVM_NUM_MMU_PAGES; i++) { - struct page *page; struct kvm_mmu_page *page_header = &vcpu->page_header_buf[i]; INIT_LIST_HEAD(&page_header->link); - if ((page = alloc_page(GFP_KVM_MMU)) == NULL) + if ((page = alloc_page(GFP_KERNEL)) == NULL) goto error_1; page->private = (unsigned long)page_header; page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT; memset(__va(page_header->page_hpa), 0, PAGE_SIZE); list_add(&page_header->link, &vcpu->free_pages); + ++vcpu->kvm->n_free_mmu_pages; } + + /* + * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64. + * Therefore we need to allocate shadow page tables in the first + * 4GB of memory, which happens to fit the DMA32 zone. + */ + page = alloc_page(GFP_KERNEL | __GFP_DMA32); + if (!page) + goto error_1; + vcpu->mmu.pae_root = page_address(page); + for (i = 0; i < 4; ++i) + vcpu->mmu.pae_root[i] = INVALID_PAGE; + return 0; error_1: @@ -639,22 +1244,22 @@ error_1: return -ENOMEM; } -int kvm_mmu_init(struct kvm_vcpu *vcpu) +int kvm_mmu_create(struct kvm_vcpu *vcpu) { - int r; - ASSERT(vcpu); ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); ASSERT(list_empty(&vcpu->free_pages)); - if ((r = alloc_mmu_pages(vcpu))) - return r; + return alloc_mmu_pages(vcpu); +} - if ((r = init_kvm_mmu(vcpu))) { - free_mmu_pages(vcpu); - return r; - } - return 0; +int kvm_mmu_setup(struct kvm_vcpu *vcpu) +{ + ASSERT(vcpu); + ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); + ASSERT(!list_empty(&vcpu->free_pages)); + + return init_kvm_mmu(vcpu); } void kvm_mmu_destroy(struct kvm_vcpu *vcpu) @@ -663,10 +1268,12 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu) destroy_kvm_mmu(vcpu); free_mmu_pages(vcpu); + mmu_free_memory_caches(vcpu); } -void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) +void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot) { + struct kvm *kvm = vcpu->kvm; struct kvm_mmu_page *page; list_for_each_entry(page, &kvm->active_mmu_pages, link) { @@ -679,8 +1286,169 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) pt = __va(page->page_hpa); for (i = 0; i < PT64_ENT_PER_PAGE; ++i) /* avoid RMW */ - if (pt[i] & PT_WRITABLE_MASK) + if (pt[i] & PT_WRITABLE_MASK) { + rmap_remove(vcpu, &pt[i]); pt[i] &= ~PT_WRITABLE_MASK; + } + } +} + +#ifdef AUDIT + +static const char *audit_msg; + +static gva_t canonicalize(gva_t gva) +{ +#ifdef CONFIG_X86_64 + gva = (long long)(gva << 16) >> 16; +#endif + return gva; +} + +static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, + gva_t va, int level) +{ + u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK); + int i; + gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { + u64 ent = pt[i]; + + if (!ent & PT_PRESENT_MASK) + continue; + va = canonicalize(va); + if (level > 1) + audit_mappings_page(vcpu, ent, va, level - 1); + else { + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, va); + hpa_t hpa = gpa_to_hpa(vcpu, gpa); + + if ((ent & PT_PRESENT_MASK) + && (ent & PT64_BASE_ADDR_MASK) != hpa) + printk(KERN_ERR "audit error: (%s) levels %d" + " gva %lx gpa %llx hpa %llx ent %llx\n", + audit_msg, vcpu->mmu.root_level, + va, gpa, hpa, ent); + } + } +} + +static void audit_mappings(struct kvm_vcpu *vcpu) +{ + int i; + + if (vcpu->mmu.root_level == 4) + audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4); + else + for (i = 0; i < 4; ++i) + if (vcpu->mmu.pae_root[i] & PT_PRESENT_MASK) + audit_mappings_page(vcpu, + vcpu->mmu.pae_root[i], + i << 30, + 2); +} + +static int count_rmaps(struct kvm_vcpu *vcpu) +{ + int nmaps = 0; + int i, j, k; + + for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { + struct kvm_memory_slot *m = &vcpu->kvm->memslots[i]; + struct kvm_rmap_desc *d; + + for (j = 0; j < m->npages; ++j) { + struct page *page = m->phys_mem[j]; + + if (!page->private) + continue; + if (!(page->private & 1)) { + ++nmaps; + continue; + } + d = (struct kvm_rmap_desc *)(page->private & ~1ul); + while (d) { + for (k = 0; k < RMAP_EXT; ++k) + if (d->shadow_ptes[k]) + ++nmaps; + else + break; + d = d->more; + } + } + } + return nmaps; +} + +static int count_writable_mappings(struct kvm_vcpu *vcpu) +{ + int nmaps = 0; + struct kvm_mmu_page *page; + int i; + + list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) { + u64 *pt = __va(page->page_hpa); + + if (page->role.level != PT_PAGE_TABLE_LEVEL) + continue; + + for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { + u64 ent = pt[i]; + + if (!(ent & PT_PRESENT_MASK)) + continue; + if (!(ent & PT_WRITABLE_MASK)) + continue; + ++nmaps; + } } + return nmaps; } + +static void audit_rmap(struct kvm_vcpu *vcpu) +{ + int n_rmap = count_rmaps(vcpu); + int n_actual = count_writable_mappings(vcpu); + + if (n_rmap != n_actual) + printk(KERN_ERR "%s: (%s) rmap %d actual %d\n", + __FUNCTION__, audit_msg, n_rmap, n_actual); +} + +static void audit_write_protection(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu_page *page; + + list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) { + hfn_t hfn; + struct page *pg; + + if (page->role.metaphysical) + continue; + + hfn = gpa_to_hpa(vcpu, (gpa_t)page->gfn << PAGE_SHIFT) + >> PAGE_SHIFT; + pg = pfn_to_page(hfn); + if (pg->private) + printk(KERN_ERR "%s: (%s) shadow page has writable" + " mappings: gfn %lx role %x\n", + __FUNCTION__, audit_msg, page->gfn, + page->role.word); + } +} + +static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) +{ + int olddbg = dbg; + + dbg = 0; + audit_msg = msg; + audit_rmap(vcpu); + audit_write_protection(vcpu); + audit_mappings(vcpu); + dbg = olddbg; +} + +#endif diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index a9771b4c5bb..149fa45fd9a 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h @@ -32,6 +32,11 @@ #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level) #define PT_PTE_COPY_MASK PT64_PTE_COPY_MASK + #ifdef CONFIG_X86_64 + #define PT_MAX_FULL_LEVELS 4 + #else + #define PT_MAX_FULL_LEVELS 2 + #endif #elif PTTYPE == 32 #define pt_element_t u32 #define guest_walker guest_walker32 @@ -42,6 +47,7 @@ #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level) #define PT_PTE_COPY_MASK PT32_PTE_COPY_MASK + #define PT_MAX_FULL_LEVELS 2 #else #error Invalid PTTYPE value #endif @@ -52,93 +58,157 @@ */ struct guest_walker { int level; + gfn_t table_gfn[PT_MAX_FULL_LEVELS]; pt_element_t *table; + pt_element_t *ptep; pt_element_t inherited_ar; + gfn_t gfn; + u32 error_code; }; -static void FNAME(init_walker)(struct guest_walker *walker, - struct kvm_vcpu *vcpu) +/* + * Fetch a guest pte for a guest virtual address + */ +static int FNAME(walk_addr)(struct guest_walker *walker, + struct kvm_vcpu *vcpu, gva_t addr, + int write_fault, int user_fault, int fetch_fault) { hpa_t hpa; struct kvm_memory_slot *slot; + pt_element_t *ptep; + pt_element_t root; + gfn_t table_gfn; + pgprintk("%s: addr %lx\n", __FUNCTION__, addr); walker->level = vcpu->mmu.root_level; - slot = gfn_to_memslot(vcpu->kvm, - (vcpu->cr3 & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); - hpa = safe_gpa_to_hpa(vcpu, vcpu->cr3 & PT64_BASE_ADDR_MASK); + walker->table = NULL; + root = vcpu->cr3; +#if PTTYPE == 64 + if (!is_long_mode(vcpu)) { + walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3]; + root = *walker->ptep; + if (!(root & PT_PRESENT_MASK)) + goto not_present; + --walker->level; + } +#endif + table_gfn = (root & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; + walker->table_gfn[walker->level - 1] = table_gfn; + pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, + walker->level - 1, table_gfn); + slot = gfn_to_memslot(vcpu->kvm, table_gfn); + hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK); walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0); - ASSERT((!kvm_arch_ops->is_long_mode(vcpu) && is_pae(vcpu)) || + ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0); - walker->table = (pt_element_t *)( (unsigned long)walker->table | - (unsigned long)(vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) ); walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; + + for (;;) { + int index = PT_INDEX(addr, walker->level); + hpa_t paddr; + + ptep = &walker->table[index]; + ASSERT(((unsigned long)walker->table & PAGE_MASK) == + ((unsigned long)ptep & PAGE_MASK)); + + if (!is_present_pte(*ptep)) + goto not_present; + + if (write_fault && !is_writeble_pte(*ptep)) + if (user_fault || is_write_protection(vcpu)) + goto access_error; + + if (user_fault && !(*ptep & PT_USER_MASK)) + goto access_error; + +#if PTTYPE == 64 + if (fetch_fault && is_nx(vcpu) && (*ptep & PT64_NX_MASK)) + goto access_error; +#endif + + if (!(*ptep & PT_ACCESSED_MASK)) + *ptep |= PT_ACCESSED_MASK; /* avoid rmw */ + + if (walker->level == PT_PAGE_TABLE_LEVEL) { + walker->gfn = (*ptep & PT_BASE_ADDR_MASK) + >> PAGE_SHIFT; + break; + } + + if (walker->level == PT_DIRECTORY_LEVEL + && (*ptep & PT_PAGE_SIZE_MASK) + && (PTTYPE == 64 || is_pse(vcpu))) { + walker->gfn = (*ptep & PT_DIR_BASE_ADDR_MASK) + >> PAGE_SHIFT; + walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL); + break; + } + + if (walker->level != 3 || is_long_mode(vcpu)) + walker->inherited_ar &= walker->table[index]; + table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; + paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK); + kunmap_atomic(walker->table, KM_USER0); + walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), + KM_USER0); + --walker->level; + walker->table_gfn[walker->level - 1 ] = table_gfn; + pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, + walker->level - 1, table_gfn); + } + walker->ptep = ptep; + pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep); + return 1; + +not_present: + walker->error_code = 0; + goto err; + +access_error: + walker->error_code = PFERR_PRESENT_MASK; + +err: + if (write_fault) + walker->error_code |= PFERR_WRITE_MASK; + if (user_fault) + walker->error_code |= PFERR_USER_MASK; + if (fetch_fault) + walker->error_code |= PFERR_FETCH_MASK; + return 0; } static void FNAME(release_walker)(struct guest_walker *walker) { - kunmap_atomic(walker->table, KM_USER0); + if (walker->table) + kunmap_atomic(walker->table, KM_USER0); } static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte, - u64 *shadow_pte, u64 access_bits) + u64 *shadow_pte, u64 access_bits, gfn_t gfn) { ASSERT(*shadow_pte == 0); access_bits &= guest_pte; *shadow_pte = (guest_pte & PT_PTE_COPY_MASK); set_pte_common(vcpu, shadow_pte, guest_pte & PT_BASE_ADDR_MASK, - guest_pte & PT_DIRTY_MASK, access_bits); + guest_pte & PT_DIRTY_MASK, access_bits, gfn); } static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde, - u64 *shadow_pte, u64 access_bits, - int index) + u64 *shadow_pte, u64 access_bits, gfn_t gfn) { gpa_t gaddr; ASSERT(*shadow_pte == 0); access_bits &= guest_pde; - gaddr = (guest_pde & PT_DIR_BASE_ADDR_MASK) + PAGE_SIZE * index; + gaddr = (gpa_t)gfn << PAGE_SHIFT; if (PTTYPE == 32 && is_cpuid_PSE36()) gaddr |= (guest_pde & PT32_DIR_PSE36_MASK) << (32 - PT32_DIR_PSE36_SHIFT); *shadow_pte = guest_pde & PT_PTE_COPY_MASK; set_pte_common(vcpu, shadow_pte, gaddr, - guest_pde & PT_DIRTY_MASK, access_bits); -} - -/* - * Fetch a guest pte from a specific level in the paging hierarchy. - */ -static pt_element_t *FNAME(fetch_guest)(struct kvm_vcpu *vcpu, - struct guest_walker *walker, - int level, - gva_t addr) -{ - - ASSERT(level > 0 && level <= walker->level); - - for (;;) { - int index = PT_INDEX(addr, walker->level); - hpa_t paddr; - - ASSERT(((unsigned long)walker->table & PAGE_MASK) == - ((unsigned long)&walker->table[index] & PAGE_MASK)); - if (level == walker->level || - !is_present_pte(walker->table[index]) || - (walker->level == PT_DIRECTORY_LEVEL && - (walker->table[index] & PT_PAGE_SIZE_MASK) && - (PTTYPE == 64 || is_pse(vcpu)))) - return &walker->table[index]; - if (walker->level != 3 || kvm_arch_ops->is_long_mode(vcpu)) - walker->inherited_ar &= walker->table[index]; - paddr = safe_gpa_to_hpa(vcpu, walker->table[index] & PT_BASE_ADDR_MASK); - kunmap_atomic(walker->table, KM_USER0); - walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT), - KM_USER0); - --walker->level; - } + guest_pde & PT_DIRTY_MASK, access_bits, gfn); } /* @@ -150,15 +220,26 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, hpa_t shadow_addr; int level; u64 *prev_shadow_ent = NULL; + pt_element_t *guest_ent = walker->ptep; + + if (!is_present_pte(*guest_ent)) + return NULL; shadow_addr = vcpu->mmu.root_hpa; level = vcpu->mmu.shadow_root_level; + if (level == PT32E_ROOT_LEVEL) { + shadow_addr = vcpu->mmu.pae_root[(addr >> 30) & 3]; + shadow_addr &= PT64_BASE_ADDR_MASK; + --level; + } for (; ; level--) { u32 index = SHADOW_PT_INDEX(addr, level); u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index; - pt_element_t *guest_ent; + struct kvm_mmu_page *shadow_page; u64 shadow_pte; + int metaphysical; + gfn_t table_gfn; if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { if (level == PT_PAGE_TABLE_LEVEL) @@ -168,21 +249,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, continue; } - if (PTTYPE == 32 && level > PT32_ROOT_LEVEL) { - ASSERT(level == PT32E_ROOT_LEVEL); - guest_ent = FNAME(fetch_guest)(vcpu, walker, - PT32_ROOT_LEVEL, addr); - } else - guest_ent = FNAME(fetch_guest)(vcpu, walker, - level, addr); - - if (!is_present_pte(*guest_ent)) - return NULL; - - /* Don't set accessed bit on PAE PDPTRs */ - if (vcpu->mmu.root_level != 3 || walker->level != 3) - *guest_ent |= PT_ACCESSED_MASK; - if (level == PT_PAGE_TABLE_LEVEL) { if (walker->level == PT_DIRECTORY_LEVEL) { @@ -190,21 +256,30 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, *prev_shadow_ent |= PT_SHADOW_PS_MARK; FNAME(set_pde)(vcpu, *guest_ent, shadow_ent, walker->inherited_ar, - PT_INDEX(addr, PT_PAGE_TABLE_LEVEL)); + walker->gfn); } else { ASSERT(walker->level == PT_PAGE_TABLE_LEVEL); - FNAME(set_pte)(vcpu, *guest_ent, shadow_ent, walker->inherited_ar); + FNAME(set_pte)(vcpu, *guest_ent, shadow_ent, + walker->inherited_ar, + walker->gfn); } return shadow_ent; } - shadow_addr = kvm_mmu_alloc_page(vcpu, shadow_ent); - if (!VALID_PAGE(shadow_addr)) - return ERR_PTR(-ENOMEM); - shadow_pte = shadow_addr | PT_PRESENT_MASK; - if (vcpu->mmu.root_level > 3 || level != 3) - shadow_pte |= PT_ACCESSED_MASK - | PT_WRITABLE_MASK | PT_USER_MASK; + if (level - 1 == PT_PAGE_TABLE_LEVEL + && walker->level == PT_DIRECTORY_LEVEL) { + metaphysical = 1; + table_gfn = (*guest_ent & PT_BASE_ADDR_MASK) + >> PAGE_SHIFT; + } else { + metaphysical = 0; + table_gfn = walker->table_gfn[level - 2]; + } + shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, + metaphysical, shadow_ent); + shadow_addr = shadow_page->page_hpa; + shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK + | PT_WRITABLE_MASK | PT_USER_MASK; *shadow_ent = shadow_pte; prev_shadow_ent = shadow_ent; } @@ -221,14 +296,16 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu, u64 *shadow_ent, struct guest_walker *walker, gva_t addr, - int user) + int user, + int *write_pt) { pt_element_t *guest_ent; int writable_shadow; gfn_t gfn; + struct kvm_mmu_page *page; if (is_writeble_pte(*shadow_ent)) - return 0; + return !user || (*shadow_ent & PT_USER_MASK); writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK; if (user) { @@ -250,17 +327,35 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu, *shadow_ent &= ~PT_USER_MASK; } - guest_ent = FNAME(fetch_guest)(vcpu, walker, PT_PAGE_TABLE_LEVEL, addr); + guest_ent = walker->ptep; if (!is_present_pte(*guest_ent)) { *shadow_ent = 0; return 0; } - gfn = (*guest_ent & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; + gfn = walker->gfn; + + if (user) { + /* + * Usermode page faults won't be for page table updates. + */ + while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) { + pgprintk("%s: zap %lx %x\n", + __FUNCTION__, gfn, page->role.word); + kvm_mmu_zap_page(vcpu, page); + } + } else if (kvm_mmu_lookup_page(vcpu, gfn)) { + pgprintk("%s: found shadow page for %lx, marking ro\n", + __FUNCTION__, gfn); + *guest_ent |= PT_DIRTY_MASK; + *write_pt = 1; + return 0; + } mark_page_dirty(vcpu->kvm, gfn); *shadow_ent |= PT_WRITABLE_MASK; *guest_ent |= PT_DIRTY_MASK; + rmap_add(vcpu, shadow_ent); return 1; } @@ -276,75 +371,73 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu, * - normal guest page fault due to the guest pte marked not present, not * writable, or not executable * - * Returns: 1 if we need to emulate the instruction, 0 otherwise + * Returns: 1 if we need to emulate the instruction, 0 otherwise, or + * a negative value on error. */ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code) { int write_fault = error_code & PFERR_WRITE_MASK; - int pte_present = error_code & PFERR_PRESENT_MASK; int user_fault = error_code & PFERR_USER_MASK; + int fetch_fault = error_code & PFERR_FETCH_MASK; struct guest_walker walker; u64 *shadow_pte; int fixed; + int write_pt = 0; + int r; + + pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code); + kvm_mmu_audit(vcpu, "pre page fault"); + + r = mmu_topup_memory_caches(vcpu); + if (r) + return r; /* * Look up the shadow pte for the faulting address. */ - for (;;) { - FNAME(init_walker)(&walker, vcpu); - shadow_pte = FNAME(fetch)(vcpu, addr, &walker); - if (IS_ERR(shadow_pte)) { /* must be -ENOMEM */ - nonpaging_flush(vcpu); - FNAME(release_walker)(&walker); - continue; - } - break; - } + r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault, + fetch_fault); /* * The page is not mapped by the guest. Let the guest handle it. */ - if (!shadow_pte) { - inject_page_fault(vcpu, addr, error_code); + if (!r) { + pgprintk("%s: guest page fault\n", __FUNCTION__); + inject_page_fault(vcpu, addr, walker.error_code); FNAME(release_walker)(&walker); return 0; } + shadow_pte = FNAME(fetch)(vcpu, addr, &walker); + pgprintk("%s: shadow pte %p %llx\n", __FUNCTION__, + shadow_pte, *shadow_pte); + /* * Update the shadow pte. */ if (write_fault) fixed = FNAME(fix_write_pf)(vcpu, shadow_pte, &walker, addr, - user_fault); + user_fault, &write_pt); else fixed = fix_read_pf(shadow_pte); + pgprintk("%s: updated shadow pte %p %llx\n", __FUNCTION__, + shadow_pte, *shadow_pte); + FNAME(release_walker)(&walker); /* * mmio: emulate if accessible, otherwise its a guest fault. */ if (is_io_pte(*shadow_pte)) { - if (may_access(*shadow_pte, write_fault, user_fault)) - return 1; - pgprintk("%s: io work, no access\n", __FUNCTION__); - inject_page_fault(vcpu, addr, - error_code | PFERR_PRESENT_MASK); - return 0; - } - - /* - * pte not present, guest page fault. - */ - if (pte_present && !fixed) { - inject_page_fault(vcpu, addr, error_code); - return 0; + return 1; } ++kvm_stat.pf_fixed; + kvm_mmu_audit(vcpu, "post page fault (fixed)"); - return 0; + return write_pt; } static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) @@ -353,9 +446,8 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) pt_element_t guest_pte; gpa_t gpa; - FNAME(init_walker)(&walker, vcpu); - guest_pte = *FNAME(fetch_guest)(vcpu, &walker, PT_PAGE_TABLE_LEVEL, - vaddr); + FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0); + guest_pte = *walker.ptep; FNAME(release_walker)(&walker); if (!is_present_pte(guest_pte)) @@ -389,3 +481,4 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) #undef PT_PTE_COPY_MASK #undef PT_NON_PTE_COPY_MASK #undef PT_DIR_BASE_ADDR_MASK +#undef PT_MAX_FULL_LEVELS diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 0e6bc8c649c..c79df79307e 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/highmem.h> +#include <linux/profile.h> #include <asm/desc.h> #include "kvm_svm.h" @@ -166,11 +167,6 @@ static inline void write_dr7(unsigned long val) asm volatile ("mov %0, %%dr7" :: "r" (val)); } -static inline int svm_is_long_mode(struct kvm_vcpu *vcpu) -{ - return vcpu->svm->vmcb->save.efer & KVM_EFER_LMA; -} - static inline void force_new_asid(struct kvm_vcpu *vcpu) { vcpu->svm->asid_generation--; @@ -240,13 +236,15 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip; vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; + + vcpu->interrupt_window_open = 1; } static int has_svm(void) { uint32_t eax, ebx, ecx, edx; - if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) { + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { printk(KERN_INFO "has_svm: not amd\n"); return 0; } @@ -402,11 +400,11 @@ static __init int svm_hardware_setup(void) set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1); set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1); set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1); - set_msr_interception(msrpm_va, MSR_STAR, 1, 1); set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1); set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1); set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1); #endif + set_msr_interception(msrpm_va, MSR_K6_STAR, 1, 1); set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1); set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1); set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1); @@ -500,11 +498,11 @@ static void init_vmcb(struct vmcb *vmcb) /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ (1ULL << INTERCEPT_CPUID) | (1ULL << INTERCEPT_HLT) | - (1ULL << INTERCEPT_INVLPG) | (1ULL << INTERCEPT_INVLPGA) | (1ULL << INTERCEPT_IOIO_PROT) | (1ULL << INTERCEPT_MSR_PROT) | (1ULL << INTERCEPT_TASK_SWITCH) | + (1ULL << INTERCEPT_SHUTDOWN) | (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL) | (1ULL << INTERCEPT_VMLOAD) | @@ -575,6 +573,8 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); init_vmcb(vcpu->svm->vmcb); + fx_init(vcpu); + return 0; out2: @@ -681,14 +681,14 @@ static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - dt->limit = vcpu->svm->vmcb->save.ldtr.limit; - dt->base = vcpu->svm->vmcb->save.ldtr.base; + dt->limit = vcpu->svm->vmcb->save.idtr.limit; + dt->base = vcpu->svm->vmcb->save.idtr.base; } static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) { - vcpu->svm->vmcb->save.ldtr.limit = dt->limit; - vcpu->svm->vmcb->save.ldtr.base = dt->base ; + vcpu->svm->vmcb->save.idtr.limit = dt->limit; + vcpu->svm->vmcb->save.idtr.base = dt->base ; } static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) @@ -703,6 +703,10 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) vcpu->svm->vmcb->save.gdtr.base = dt->base ; } +static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu) +{ +} + static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { #ifdef CONFIG_X86_64 @@ -850,6 +854,7 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) u64 fault_address; u32 error_code; enum emulation_result er; + int r; if (is_external_interrupt(exit_int_info)) push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); @@ -858,7 +863,12 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) fault_address = vcpu->svm->vmcb->control.exit_info_2; error_code = vcpu->svm->vmcb->control.exit_info_1; - if (!vcpu->mmu.page_fault(vcpu, fault_address, error_code)) { + r = kvm_mmu_page_fault(vcpu, fault_address, error_code); + if (r < 0) { + spin_unlock(&vcpu->kvm->lock); + return r; + } + if (!r) { spin_unlock(&vcpu->kvm->lock); return 1; } @@ -883,6 +893,19 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } +static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + /* + * VMCB is undefined after a SHUTDOWN intercept + * so reinitialize it. + */ + memset(vcpu->svm->vmcb, 0, PAGE_SIZE); + init_vmcb(vcpu->svm->vmcb); + + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + return 0; +} + static int io_get_override(struct kvm_vcpu *vcpu, struct vmcb_seg **seg, int *addr_override) @@ -1034,10 +1057,11 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; skip_emulated_instruction(vcpu); - if (vcpu->irq_summary && (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)) + if (vcpu->irq_summary) return 1; kvm_run->exit_reason = KVM_EXIT_HLT; + ++kvm_stat.halt_exits; return 0; } @@ -1071,20 +1095,6 @@ static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_ru static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) { switch (ecx) { - case MSR_IA32_MC0_CTL: - case MSR_IA32_MCG_STATUS: - case MSR_IA32_MCG_CAP: - case MSR_IA32_MC0_MISC: - case MSR_IA32_MC0_MISC+4: - case MSR_IA32_MC0_MISC+8: - case MSR_IA32_MC0_MISC+12: - case MSR_IA32_MC0_MISC+16: - case MSR_IA32_UCODE_REV: - /* MTRR registers */ - case 0xfe: - case 0x200 ... 0x2ff: - *data = 0; - break; case MSR_IA32_TIME_STAMP_COUNTER: { u64 tsc; @@ -1092,16 +1102,10 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) *data = vcpu->svm->vmcb->control.tsc_offset + tsc; break; } - case MSR_EFER: - *data = vcpu->shadow_efer; - break; - case MSR_IA32_APICBASE: - *data = vcpu->apic_base; - break; -#ifdef CONFIG_X86_64 - case MSR_STAR: + case MSR_K6_STAR: *data = vcpu->svm->vmcb->save.star; break; +#ifdef CONFIG_X86_64 case MSR_LSTAR: *data = vcpu->svm->vmcb->save.lstar; break; @@ -1125,8 +1129,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) *data = vcpu->svm->vmcb->save.sysenter_esp; break; default: - printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", ecx); - return 1; + return kvm_get_msr_common(vcpu, ecx, data); } return 0; } @@ -1150,15 +1153,6 @@ static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) { switch (ecx) { -#ifdef CONFIG_X86_64 - case MSR_EFER: - set_efer(vcpu, data); - break; -#endif - case MSR_IA32_MC0_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n" - , __FUNCTION__, data); - break; case MSR_IA32_TIME_STAMP_COUNTER: { u64 tsc; @@ -1166,17 +1160,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) vcpu->svm->vmcb->control.tsc_offset = data - tsc; break; } - case MSR_IA32_UCODE_REV: - case MSR_IA32_UCODE_WRITE: - case 0x200 ... 0x2ff: /* MTRRs */ - break; - case MSR_IA32_APICBASE: - vcpu->apic_base = data; - break; -#ifdef CONFIG_X86_64_ - case MSR_STAR: + case MSR_K6_STAR: vcpu->svm->vmcb->save.star = data; break; +#ifdef CONFIG_X86_64 case MSR_LSTAR: vcpu->svm->vmcb->save.lstar = data; break; @@ -1200,8 +1187,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) vcpu->svm->vmcb->save.sysenter_esp = data; break; default: - printk(KERN_ERR "kvm: unhandled wrmsr: %x\n", ecx); - return 1; + return kvm_set_msr_common(vcpu, ecx, data); } return 0; } @@ -1227,6 +1213,23 @@ static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return rdmsr_interception(vcpu, kvm_run); } +static int interrupt_window_interception(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + /* + * If the user space waits to inject interrupts, exit as soon as + * possible + */ + if (kvm_run->request_interrupt_window && + !vcpu->irq_summary) { + ++kvm_stat.irq_window_exits; + kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; + return 0; + } + + return 1; +} + static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) = { [SVM_EXIT_READ_CR0] = emulate_on_interception, @@ -1251,6 +1254,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, [SVM_EXIT_NMI] = nop_on_interception, [SVM_EXIT_SMI] = nop_on_interception, [SVM_EXIT_INIT] = nop_on_interception, + [SVM_EXIT_VINTR] = interrupt_window_interception, /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ [SVM_EXIT_CPUID] = cpuid_interception, [SVM_EXIT_HLT] = halt_interception, @@ -1259,6 +1263,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, [SVM_EXIT_IOIO] = io_interception, [SVM_EXIT_MSR] = msr_interception, [SVM_EXIT_TASK_SWITCH] = task_switch_interception, + [SVM_EXIT_SHUTDOWN] = shutdown_interception, [SVM_EXIT_VMRUN] = invalid_op_interception, [SVM_EXIT_VMMCALL] = invalid_op_interception, [SVM_EXIT_VMLOAD] = invalid_op_interception, @@ -1319,15 +1324,11 @@ static void pre_svm_run(struct kvm_vcpu *vcpu) } -static inline void kvm_try_inject_irq(struct kvm_vcpu *vcpu) +static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu) { struct vmcb_control_area *control; - if (!vcpu->irq_summary) - return; - control = &vcpu->svm->vmcb->control; - control->int_vector = pop_irq(vcpu); control->int_ctl &= ~V_INTR_PRIO_MASK; control->int_ctl |= V_IRQ_MASK | @@ -1342,6 +1343,59 @@ static void kvm_reput_irq(struct kvm_vcpu *vcpu) control->int_ctl &= ~V_IRQ_MASK; push_irq(vcpu, control->int_vector); } + + vcpu->interrupt_window_open = + !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); +} + +static void do_interrupt_requests(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + struct vmcb_control_area *control = &vcpu->svm->vmcb->control; + + vcpu->interrupt_window_open = + (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && + (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)); + + if (vcpu->interrupt_window_open && vcpu->irq_summary) + /* + * If interrupts enabled, and not blocked by sti or mov ss. Good. + */ + kvm_do_inject_irq(vcpu); + + /* + * Interrupts blocked. Wait for unblock. + */ + if (!vcpu->interrupt_window_open && + (vcpu->irq_summary || kvm_run->request_interrupt_window)) { + control->intercept |= 1ULL << INTERCEPT_VINTR; + } else + control->intercept &= ~(1ULL << INTERCEPT_VINTR); +} + +static void post_kvm_run_save(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && + vcpu->irq_summary == 0); + kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0; + kvm_run->cr8 = vcpu->cr8; + kvm_run->apic_base = vcpu->apic_base; +} + +/* + * Check if userspace requested an interrupt window, and that the + * interrupt window is open. + * + * No need to exit to userspace if we already have an interrupt queued. + */ +static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + return (!vcpu->irq_summary && + kvm_run->request_interrupt_window && + vcpu->interrupt_window_open && + (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)); } static void save_db_regs(unsigned long *db_regs) @@ -1365,9 +1419,11 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) u16 fs_selector; u16 gs_selector; u16 ldt_selector; + int r; again: - kvm_try_inject_irq(vcpu); + if (!vcpu->mmio_read_completed) + do_interrupt_requests(vcpu, kvm_run); clgi(); @@ -1387,6 +1443,10 @@ again: save_db_regs(vcpu->svm->host_db_regs); load_db_regs(vcpu->svm->db_regs); } + + fx_save(vcpu->host_fx_image); + fx_restore(vcpu->guest_fx_image); + asm volatile ( #ifdef CONFIG_X86_64 "push %%rbx; push %%rcx; push %%rdx;" @@ -1496,6 +1556,9 @@ again: #endif : "cc", "memory" ); + fx_save(vcpu->guest_fx_image); + fx_restore(vcpu->host_fx_image); + if ((vcpu->svm->vmcb->save.dr7 & 0xff)) load_db_regs(vcpu->svm->host_db_regs); @@ -1512,6 +1575,13 @@ again: reload_tss(vcpu); + /* + * Profile KVM exit RIPs: + */ + if (unlikely(prof_on == KVM_PROFILING)) + profile_hit(KVM_PROFILING, + (void *)(unsigned long)vcpu->svm->vmcb->save.rip); + stgi(); kvm_reput_irq(vcpu); @@ -1521,18 +1591,28 @@ again: if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code; + post_kvm_run_save(vcpu, kvm_run); return 0; } - if (handle_exit(vcpu, kvm_run)) { + r = handle_exit(vcpu, kvm_run); + if (r > 0) { if (signal_pending(current)) { ++kvm_stat.signal_exits; + post_kvm_run_save(vcpu, kvm_run); + return -EINTR; + } + + if (dm_request_for_irq_injection(vcpu, kvm_run)) { + ++kvm_stat.request_irq_exits; + post_kvm_run_save(vcpu, kvm_run); return -EINTR; } kvm_resched(vcpu); goto again; } - return 0; + post_kvm_run_save(vcpu, kvm_run); + return r; } static void svm_flush_tlb(struct kvm_vcpu *vcpu) @@ -1598,8 +1678,8 @@ static struct kvm_arch_ops svm_arch_ops = { .get_segment_base = svm_get_segment_base, .get_segment = svm_get_segment, .set_segment = svm_set_segment, - .is_long_mode = svm_is_long_mode, .get_cs_db_l_bits = svm_get_cs_db_l_bits, + .decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits, .set_cr0 = svm_set_cr0, .set_cr0_no_modeswitch = svm_set_cr0, .set_cr3 = svm_set_cr3, diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index f0f0b1a781f..54c35c0b318 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -21,12 +21,12 @@ #include <linux/module.h> #include <linux/mm.h> #include <linux/highmem.h> +#include <linux/profile.h> #include <asm/io.h> #include <asm/desc.h> #include "segment_descriptor.h" -#define MSR_IA32_FEATURE_CONTROL 0x03a MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -117,7 +117,7 @@ static void vmcs_clear(struct vmcs *vmcs) static void __vcpu_clear(void *arg) { struct kvm_vcpu *vcpu = arg; - int cpu = smp_processor_id(); + int cpu = raw_smp_processor_id(); if (vcpu->cpu == cpu) vmcs_clear(vcpu->vmcs); @@ -153,15 +153,21 @@ static u64 vmcs_read64(unsigned long field) #endif } +static noinline void vmwrite_error(unsigned long field, unsigned long value) +{ + printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", + field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); + dump_stack(); +} + static void vmcs_writel(unsigned long field, unsigned long value) { u8 error; asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0" : "=q"(error) : "a"(value), "d"(field) : "cc" ); - if (error) - printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", - field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); + if (unlikely(error)) + vmwrite_error(field, value); } static void vmcs_write16(unsigned long field, u16 value) @@ -264,6 +270,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) if (interruptibility & 3) vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility & ~3); + vcpu->interrupt_window_open = 1; } static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) @@ -344,8 +351,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) data = vmcs_readl(GUEST_GS_BASE); break; case MSR_EFER: - data = vcpu->shadow_efer; - break; + return kvm_get_msr_common(vcpu, msr_index, pdata); #endif case MSR_IA32_TIME_STAMP_COUNTER: data = guest_read_tsc(); @@ -359,31 +365,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) case MSR_IA32_SYSENTER_ESP: data = vmcs_read32(GUEST_SYSENTER_ESP); break; - case MSR_IA32_MC0_CTL: - case MSR_IA32_MCG_STATUS: - case MSR_IA32_MCG_CAP: - case MSR_IA32_MC0_MISC: - case MSR_IA32_MC0_MISC+4: - case MSR_IA32_MC0_MISC+8: - case MSR_IA32_MC0_MISC+12: - case MSR_IA32_MC0_MISC+16: - case MSR_IA32_UCODE_REV: - /* MTRR registers */ - case 0xfe: - case 0x200 ... 0x2ff: - data = 0; - break; - case MSR_IA32_APICBASE: - data = vcpu->apic_base; - break; default: msr = find_msr_entry(vcpu, msr_index); - if (!msr) { - printk(KERN_ERR "kvm: unhandled rdmsr: %x\n", msr_index); - return 1; + if (msr) { + data = msr->data; + break; } - data = msr->data; - break; + return kvm_get_msr_common(vcpu, msr_index, pdata); } *pdata = data; @@ -400,6 +388,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) struct vmx_msr_entry *msr; switch (msr_index) { #ifdef CONFIG_X86_64 + case MSR_EFER: + return kvm_set_msr_common(vcpu, msr_index, data); case MSR_FS_BASE: vmcs_writel(GUEST_FS_BASE, data); break; @@ -416,32 +406,17 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) case MSR_IA32_SYSENTER_ESP: vmcs_write32(GUEST_SYSENTER_ESP, data); break; -#ifdef __x86_64 - case MSR_EFER: - set_efer(vcpu, data); - break; - case MSR_IA32_MC0_STATUS: - printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n" - , __FUNCTION__, data); - break; -#endif case MSR_IA32_TIME_STAMP_COUNTER: { guest_write_tsc(data); break; } - case MSR_IA32_UCODE_REV: - case MSR_IA32_UCODE_WRITE: - case 0x200 ... 0x2ff: /* MTRRs */ - break; - case MSR_IA32_APICBASE: - vcpu->apic_base = data; - break; default: msr = find_msr_entry(vcpu, msr_index); - if (!msr) { - printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr_index); - return 1; + if (msr) { + msr->data = data; + break; } + return kvm_set_msr_common(vcpu, msr_index, data); msr->data = data; break; } @@ -551,11 +526,11 @@ static __init void setup_vmcs_descriptor(void) { u32 vmx_msr_low, vmx_msr_high; - rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high); + rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); vmcs_descriptor.size = vmx_msr_high & 0x1fff; vmcs_descriptor.order = get_order(vmcs_descriptor.size); vmcs_descriptor.revision_id = vmx_msr_low; -}; +} static struct vmcs *alloc_vmcs_cpu(int cpu) { @@ -574,7 +549,7 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) static struct vmcs *alloc_vmcs(void) { - return alloc_vmcs_cpu(smp_processor_id()); + return alloc_vmcs_cpu(raw_smp_processor_id()); } static void free_vmcs(struct vmcs *vmcs) @@ -726,6 +701,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_SS_AR_BYTES, 0xf3); vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); + vmcs_write32(GUEST_CS_LIMIT, 0xffff); vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4); fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es); @@ -768,6 +744,15 @@ static void exit_lmode(struct kvm_vcpu *vcpu) #endif +static void vmx_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu) +{ + vcpu->cr0 &= KVM_GUEST_CR0_MASK; + vcpu->cr0 |= vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK; + + vcpu->cr4 &= KVM_GUEST_CR4_MASK; + vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK; +} + static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { if (vcpu->rmode.active && (cr0 & CR0_PE_MASK)) @@ -897,11 +882,6 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, vmcs_write32(sf->ar_bytes, ar); } -static int vmx_is_long_mode(struct kvm_vcpu *vcpu) -{ - return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK; -} - static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) { u32 ar = vmcs_read32(GUEST_CS_AR_BYTES); @@ -1048,8 +1028,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_writel(GUEST_RIP, 0xfff0); vmcs_writel(GUEST_RSP, 0); - vmcs_writel(GUEST_CR3, 0); - //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 vmcs_writel(GUEST_DR7, 0x400); @@ -1075,18 +1053,17 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_write64(GUEST_IA32_DEBUGCTL, 0); /* Control */ - vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS_MSR, + vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS, PIN_BASED_VM_EXEC_CONTROL, PIN_BASED_EXT_INTR_MASK /* 20.6.1 */ | PIN_BASED_NMI_EXITING /* 20.6.1 */ ); - vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS_MSR, + vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS, CPU_BASED_VM_EXEC_CONTROL, CPU_BASED_HLT_EXITING /* 20.6.2 */ | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */ | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */ | CPU_BASED_UNCOND_IO_EXITING /* 20.6.2 */ - | CPU_BASED_INVDPG_EXITING | CPU_BASED_MOV_DR_EXITING | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */ ); @@ -1131,14 +1108,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) rdmsrl(MSR_IA32_SYSENTER_EIP, a); vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ - ret = -ENOMEM; - vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vcpu->guest_msrs) - goto out; - vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vcpu->host_msrs) - goto out_free_guest_msrs; - for (i = 0; i < NR_VMX_MSR; ++i) { u32 index = vmx_msr_index[i]; u32 data_low, data_high; @@ -1147,6 +1116,8 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) if (rdmsr_safe(index, &data_low, &data_high) < 0) continue; + if (wrmsr_safe(index, data_low, data_high) < 0) + continue; data = data_low | ((u64)data_high << 32); vcpu->host_msrs[j].index = index; vcpu->host_msrs[j].reserved = 0; @@ -1163,7 +1134,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); vmcs_writel(VM_EXIT_MSR_LOAD_ADDR, virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS)); - vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS_MSR, VM_EXIT_CONTROLS, + vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */ vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ @@ -1171,7 +1142,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) /* 22.2.1, 20.8.1 */ - vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS_MSR, + vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, VM_ENTRY_CONTROLS, 0); vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ @@ -1192,8 +1163,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) return 0; -out_free_guest_msrs: - kfree(vcpu->guest_msrs); out: return ret; } @@ -1261,21 +1230,34 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } -static void kvm_try_inject_irq(struct kvm_vcpu *vcpu) + +static void do_interrupt_requests(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) { - if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) - && (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0) + u32 cpu_based_vm_exec_control; + + vcpu->interrupt_window_open = + ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); + + if (vcpu->interrupt_window_open && + vcpu->irq_summary && + !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK)) /* - * Interrupts enabled, and not blocked by sti or mov ss. Good. + * If interrupts enabled, and not blocked by sti or mov ss. Good. */ kvm_do_inject_irq(vcpu); - else + + cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + if (!vcpu->interrupt_window_open && + (vcpu->irq_summary || kvm_run->request_interrupt_window)) /* * Interrupts blocked. Wait for unblock. */ - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, - vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) - | CPU_BASED_VIRTUAL_INTR_PENDING); + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; + else + cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); } static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu) @@ -1314,6 +1296,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) unsigned long cr2, rip; u32 vect_info; enum emulation_result er; + int r; vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); intr_info = vmcs_read32(VM_EXIT_INTR_INFO); @@ -1342,7 +1325,12 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) cr2 = vmcs_readl(EXIT_QUALIFICATION); spin_lock(&vcpu->kvm->lock); - if (!vcpu->mmu.page_fault(vcpu, cr2, error_code)) { + r = kvm_mmu_page_fault(vcpu, cr2, error_code); + if (r < 0) { + spin_unlock(&vcpu->kvm->lock); + return r; + } + if (!r) { spin_unlock(&vcpu->kvm->lock); return 1; } @@ -1462,17 +1450,6 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } -static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - u64 address = vmcs_read64(EXIT_QUALIFICATION); - int instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); - spin_lock(&vcpu->kvm->lock); - vcpu->mmu.inval_page(vcpu, address); - spin_unlock(&vcpu->kvm->lock); - vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP) + instruction_length); - return 1; -} - static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u64 exit_qualification; @@ -1612,23 +1589,40 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; } +static void post_kvm_run_save(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0; + kvm_run->cr8 = vcpu->cr8; + kvm_run->apic_base = vcpu->apic_base; + kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && + vcpu->irq_summary == 0); +} + static int handle_interrupt_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - /* Turn off interrupt window reporting. */ - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, - vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) - & ~CPU_BASED_VIRTUAL_INTR_PENDING); + /* + * If the user space waits to inject interrupts, exit as soon as + * possible + */ + if (kvm_run->request_interrupt_window && + !vcpu->irq_summary) { + kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; + ++kvm_stat.irq_window_exits; + return 0; + } return 1; } static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { skip_emulated_instruction(vcpu); - if (vcpu->irq_summary && (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)) + if (vcpu->irq_summary) return 1; kvm_run->exit_reason = KVM_EXIT_HLT; + ++kvm_stat.halt_exits; return 0; } @@ -1642,7 +1636,6 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, [EXIT_REASON_EXCEPTION_NMI] = handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, [EXIT_REASON_IO_INSTRUCTION] = handle_io, - [EXIT_REASON_INVLPG] = handle_invlpg, [EXIT_REASON_CR_ACCESS] = handle_cr, [EXIT_REASON_DR_ACCESS] = handle_dr, [EXIT_REASON_CPUID] = handle_cpuid, @@ -1679,11 +1672,27 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) return 0; } +/* + * Check if userspace requested an interrupt window, and that the + * interrupt window is open. + * + * No need to exit to userspace if we already have an interrupt queued. + */ +static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, + struct kvm_run *kvm_run) +{ + return (!vcpu->irq_summary && + kvm_run->request_interrupt_window && + vcpu->interrupt_window_open && + (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)); +} + static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u8 fail; u16 fs_sel, gs_sel, ldt_sel; int fs_gs_ldt_reload_needed; + int r; again: /* @@ -1710,9 +1719,8 @@ again: vmcs_writel(HOST_GS_BASE, segment_base(gs_sel)); #endif - if (vcpu->irq_summary && - !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK)) - kvm_try_inject_irq(vcpu); + if (!vcpu->mmio_read_completed) + do_interrupt_requests(vcpu, kvm_run); if (vcpu->guest_debug.enabled) kvm_guest_debug_pre(vcpu); @@ -1819,7 +1827,7 @@ again: #endif "setbe %0 \n\t" "popf \n\t" - : "=g" (fail) + : "=q" (fail) : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP), "c"(vcpu), [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])), @@ -1849,15 +1857,23 @@ again: fx_save(vcpu->guest_fx_image); fx_restore(vcpu->host_fx_image); + vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; #ifndef CONFIG_X86_64 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); #endif + /* + * Profile KVM exit RIPs: + */ + if (unlikely(prof_on == KVM_PROFILING)) + profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); + kvm_run->exit_type = 0; if (fail) { kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR); + r = 0; } else { if (fs_gs_ldt_reload_needed) { load_ldt(ldt_sel); @@ -1877,17 +1893,28 @@ again: } vcpu->launched = 1; kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; - if (kvm_handle_exit(kvm_run, vcpu)) { + r = kvm_handle_exit(kvm_run, vcpu); + if (r > 0) { /* Give scheduler a change to reschedule. */ if (signal_pending(current)) { ++kvm_stat.signal_exits; + post_kvm_run_save(vcpu, kvm_run); + return -EINTR; + } + + if (dm_request_for_irq_injection(vcpu, kvm_run)) { + ++kvm_stat.request_irq_exits; + post_kvm_run_save(vcpu, kvm_run); return -EINTR; } + kvm_resched(vcpu); goto again; } } - return 0; + + post_kvm_run_save(vcpu, kvm_run); + return r; } static void vmx_flush_tlb(struct kvm_vcpu *vcpu) @@ -1943,13 +1970,33 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu) { struct vmcs *vmcs; + vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vcpu->guest_msrs) + return -ENOMEM; + + vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!vcpu->host_msrs) + goto out_free_guest_msrs; + vmcs = alloc_vmcs(); if (!vmcs) - return -ENOMEM; + goto out_free_msrs; + vmcs_clear(vmcs); vcpu->vmcs = vmcs; vcpu->launched = 0; + return 0; + +out_free_msrs: + kfree(vcpu->host_msrs); + vcpu->host_msrs = NULL; + +out_free_guest_msrs: + kfree(vcpu->guest_msrs); + vcpu->guest_msrs = NULL; + + return -ENOMEM; } static struct kvm_arch_ops vmx_arch_ops = { @@ -1972,8 +2019,8 @@ static struct kvm_arch_ops vmx_arch_ops = { .get_segment_base = vmx_get_segment_base, .get_segment = vmx_get_segment, .set_segment = vmx_set_segment, - .is_long_mode = vmx_is_long_mode, .get_cs_db_l_bits = vmx_get_cs_db_l_bits, + .decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits, .set_cr0 = vmx_set_cr0, .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch, .set_cr3 = vmx_set_cr3, diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h index 79727834158..4c0ab151836 100644 --- a/drivers/kvm/vmx.h +++ b/drivers/kvm/vmx.h @@ -286,11 +286,11 @@ enum vmcs_field { #define CR4_VMXE 0x2000 -#define MSR_IA32_VMX_BASIC_MSR 0x480 +#define MSR_IA32_VMX_BASIC 0x480 #define MSR_IA32_FEATURE_CONTROL 0x03a -#define MSR_IA32_VMX_PINBASED_CTLS_MSR 0x481 -#define MSR_IA32_VMX_PROCBASED_CTLS_MSR 0x482 -#define MSR_IA32_VMX_EXIT_CTLS_MSR 0x483 -#define MSR_IA32_VMX_ENTRY_CTLS_MSR 0x484 +#define MSR_IA32_VMX_PINBASED_CTLS 0x481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 +#define MSR_IA32_VMX_EXIT_CTLS 0x483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x484 #endif diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 1bff3e925fd..7513cddb929 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -61,6 +61,7 @@ #define ModRM (1<<6) /* Destination is only written; never read. */ #define Mov (1<<7) +#define BitOp (1<<8) static u8 opcode_table[256] = { /* 0x00 - 0x07 */ @@ -148,7 +149,7 @@ static u8 opcode_table[256] = { 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM }; -static u8 twobyte_table[256] = { +static u16 twobyte_table[256] = { /* 0x00 - 0x0F */ 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, @@ -180,16 +181,16 @@ static u8 twobyte_table[256] = { /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ - 0, 0, 0, DstMem | SrcReg | ModRM, 0, 0, 0, 0, + 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, /* 0xA8 - 0xAF */ - 0, 0, 0, DstMem | SrcReg | ModRM, 0, 0, 0, 0, + 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, /* 0xB0 - 0xB7 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0, - DstMem | SrcReg | ModRM, + DstMem | SrcReg | ModRM | BitOp, 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem16 | ModRM | Mov, /* 0xB8 - 0xBF */ - 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM, + 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp, 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem16 | ModRM | Mov, /* 0xC0 - 0xCF */ @@ -469,7 +470,8 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt, int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { - u8 b, d, sib, twobyte = 0, rex_prefix = 0; + unsigned d; + u8 b, sib, twobyte = 0, rex_prefix = 0; u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; unsigned long *override_base = NULL; unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; @@ -726,46 +728,6 @@ done_prefixes: ; } - /* Decode and fetch the destination operand: register or memory. */ - switch (d & DstMask) { - case ImplicitOps: - /* Special instructions do their own operand decoding. */ - goto special_insn; - case DstReg: - dst.type = OP_REG; - if ((d & ByteOp) - && !(twobyte_table && (b == 0xb6 || b == 0xb7))) { - dst.ptr = decode_register(modrm_reg, _regs, - (rex_prefix == 0)); - dst.val = *(u8 *) dst.ptr; - dst.bytes = 1; - } else { - dst.ptr = decode_register(modrm_reg, _regs, 0); - switch ((dst.bytes = op_bytes)) { - case 2: - dst.val = *(u16 *)dst.ptr; - break; - case 4: - dst.val = *(u32 *)dst.ptr; - break; - case 8: - dst.val = *(u64 *)dst.ptr; - break; - } - } - break; - case DstMem: - dst.type = OP_MEM; - dst.ptr = (unsigned long *)cr2; - dst.bytes = (d & ByteOp) ? 1 : op_bytes; - if (!(d & Mov) && /* optimisation - avoid slow emulated read */ - ((rc = ops->read_emulated((unsigned long)dst.ptr, - &dst.val, dst.bytes, ctxt)) != 0)) - goto done; - break; - } - dst.orig_val = dst.val; - /* * Decode and fetch the source operand: register, memory * or immediate. @@ -838,6 +800,50 @@ done_prefixes: break; } + /* Decode and fetch the destination operand: register or memory. */ + switch (d & DstMask) { + case ImplicitOps: + /* Special instructions do their own operand decoding. */ + goto special_insn; + case DstReg: + dst.type = OP_REG; + if ((d & ByteOp) + && !(twobyte_table && (b == 0xb6 || b == 0xb7))) { + dst.ptr = decode_register(modrm_reg, _regs, + (rex_prefix == 0)); + dst.val = *(u8 *) dst.ptr; + dst.bytes = 1; + } else { + dst.ptr = decode_register(modrm_reg, _regs, 0); + switch ((dst.bytes = op_bytes)) { + case 2: + dst.val = *(u16 *)dst.ptr; + break; + case 4: + dst.val = *(u32 *)dst.ptr; + break; + case 8: + dst.val = *(u64 *)dst.ptr; + break; + } + } + break; + case DstMem: + dst.type = OP_MEM; + dst.ptr = (unsigned long *)cr2; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + if (d & BitOp) { + dst.ptr += src.val / BITS_PER_LONG; + dst.bytes = sizeof(long); + } + if (!(d & Mov) && /* optimisation - avoid slow emulated read */ + ((rc = ops->read_emulated((unsigned long)dst.ptr, + &dst.val, dst.bytes, ctxt)) != 0)) + goto done; + break; + } + dst.orig_val = dst.val; + if (twobyte) goto twobyte_insn; @@ -1323,7 +1329,7 @@ twobyte_special_insn: ctxt)) != 0)) goto done; if ((old_lo != _regs[VCPU_REGS_RAX]) - || (old_hi != _regs[VCPU_REGS_RDI])) { + || (old_hi != _regs[VCPU_REGS_RDX])) { _regs[VCPU_REGS_RAX] = old_lo; _regs[VCPU_REGS_RDX] = old_hi; _eflags &= ~EFLG_ZF; diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index fb1edc1c9ed..50914439d86 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -16,7 +16,7 @@ #include <linux/platform_device.h> #include <linux/leds.h> -#include <asm/arch/hardware.h> +#include <asm/hardware.h> #include <asm/arch/regs-gpio.h> #include <asm/arch/leds-gpio.h> diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 6c29fe727c0..801a974342f 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -147,7 +147,7 @@ void __init pmu_backlight_init() snprintf(name, sizeof(name), "pmubl"); - bd = backlight_device_register(name, NULL, &pmu_backlight_data); + bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data); if (IS_ERR(bd)) { printk("pmubl: Backlight registration failed\n"); goto error; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index c8558d4ed50..8ca75e52f63 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -44,6 +44,7 @@ #include <linux/sysdev.h> #include <linux/freezer.h> #include <linux/syscalls.h> +#include <linux/suspend.h> #include <linux/cpu.h> #include <asm/prom.h> #include <asm/machdep.h> diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 5432d07c074..11108165e26 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -479,9 +479,12 @@ static int bitmap_read_sb(struct bitmap *bitmap) int err = -EINVAL; /* page 0 is the superblock, read it... */ - if (bitmap->file) - bitmap->sb_page = read_page(bitmap->file, 0, bitmap, PAGE_SIZE); - else { + if (bitmap->file) { + loff_t isize = i_size_read(bitmap->file->f_mapping->host); + int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize; + + bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes); + } else { bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); } if (IS_ERR(bitmap->sb_page)) { @@ -877,7 +880,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) int count; /* unmap the old page, we're done with it */ if (index == num_pages-1) - count = bytes - index * PAGE_SIZE; + count = bytes + sizeof(bitmap_super_t) + - index * PAGE_SIZE; else count = PAGE_SIZE; if (index == 0) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fe7c56e1043..3668b170ea6 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1116,7 +1116,8 @@ static int __bind(struct mapped_device *md, struct dm_table *t) if (size != get_capacity(md->disk)) memset(&md->geometry, 0, sizeof(md->geometry)); - __set_size(md, size); + if (md->suspended_bdev) + __set_size(md, size); if (size == 0) return 0; @@ -1264,6 +1265,11 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) if (!dm_suspended(md)) goto out; + /* without bdev, the device size cannot be changed */ + if (!md->suspended_bdev) + if (get_capacity(md->disk) != dm_table_get_size(table)) + goto out; + __unbind(md); r = __bind(md, table); @@ -1341,11 +1347,14 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) /* This does not get reverted if there's an error later. */ dm_table_presuspend_targets(map); - md->suspended_bdev = bdget_disk(md->disk, 0); - if (!md->suspended_bdev) { - DMWARN("bdget failed in dm_suspend"); - r = -ENOMEM; - goto flush_and_out; + /* bdget() can stall if the pending I/Os are not flushed */ + if (!noflush) { + md->suspended_bdev = bdget_disk(md->disk, 0); + if (!md->suspended_bdev) { + DMWARN("bdget failed in dm_suspend"); + r = -ENOMEM; + goto flush_and_out; + } } /* @@ -1473,8 +1482,10 @@ int dm_resume(struct mapped_device *md) unlock_fs(md); - bdput(md->suspended_bdev); - md->suspended_bdev = NULL; + if (md->suspended_bdev) { + bdput(md->suspended_bdev); + md->suspended_bdev = NULL; + } clear_bit(DMF_SUSPENDED, &md->flags); diff --git a/drivers/md/md.c b/drivers/md/md.c index 21e2a7b0884..e8807ea5377 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1633,7 +1633,8 @@ repeat: * and 'events' is odd, we can roll back to the previous clean state */ if (nospares && (mddev->in_sync && mddev->recovery_cp == MaxSector) - && (mddev->events & 1)) + && (mddev->events & 1) + && mddev->events != 1) mddev->events--; else { /* otherwise we have to go forward and ... */ @@ -1792,7 +1793,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) else { mddev_t *mddev = rdev->mddev; kick_rdev_from_array(rdev); - md_update_sb(mddev, 1); + if (mddev->pers) + md_update_sb(mddev, 1); md_new_event(mddev); err = 0; } @@ -2004,6 +2006,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi rdev->desc_nr = -1; rdev->saved_raid_disk = -1; + rdev->raid_disk = -1; rdev->flags = 0; rdev->data_offset = 0; rdev->sb_events = 0; @@ -2233,7 +2236,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks); static ssize_t raid_disks_store(mddev_t *mddev, const char *buf, size_t len) { - /* can only set raid_disks if array is not yet active */ char *e; int rv = 0; unsigned long n = simple_strtoul(buf, &e, 10); @@ -2631,7 +2633,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len) return -EINVAL; buf = e+1; minor = simple_strtoul(buf, &e, 10); - if (e==buf || *e != '\n') + if (e==buf || (*e && *e != '\n') ) return -EINVAL; if (major >= sizeof(super_types)/sizeof(super_types[0]) || super_types[major].name == NULL) @@ -3562,6 +3564,8 @@ static int get_bitmap_file(mddev_t * mddev, void __user * arg) char *ptr, *buf = NULL; int err = -ENOMEM; + md_allow_write(mddev); + file = kmalloc(sizeof(*file), GFP_KERNEL); if (!file) goto out; @@ -3980,6 +3984,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) mddev->major_version = info->major_version; mddev->minor_version = info->minor_version; mddev->patch_version = info->patch_version; + mddev->persistent = !info->not_persistent; return 0; } mddev->major_version = MD_MAJOR_VERSION; @@ -4304,9 +4309,10 @@ static int md_ioctl(struct inode *inode, struct file *file, * Commands querying/configuring an existing array: */ /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY, - * RUN_ARRAY, and SET_BITMAP_FILE are allowed */ + * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */ if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY - && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE) { + && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE + && cmd != GET_BITMAP_FILE) { err = -ENODEV; goto abort_unlock; } @@ -5028,6 +5034,33 @@ void md_write_end(mddev_t *mddev) } } +/* md_allow_write(mddev) + * Calling this ensures that the array is marked 'active' so that writes + * may proceed without blocking. It is important to call this before + * attempting a GFP_KERNEL allocation while holding the mddev lock. + * Must be called with mddev_lock held. + */ +void md_allow_write(mddev_t *mddev) +{ + if (!mddev->pers) + return; + if (mddev->ro) + return; + + spin_lock_irq(&mddev->write_lock); + if (mddev->in_sync) { + mddev->in_sync = 0; + set_bit(MD_CHANGE_CLEAN, &mddev->flags); + if (mddev->safemode_delay && + mddev->safemode == 0) + mddev->safemode = 1; + spin_unlock_irq(&mddev->write_lock); + md_update_sb(mddev, 0); + } else + spin_unlock_irq(&mddev->write_lock); +} +EXPORT_SYMBOL_GPL(md_allow_write); + static DECLARE_WAIT_QUEUE_HEAD(resync_wait); #define SYNC_MARKS 10 diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index b30f74be398..97ee870b265 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -775,6 +775,7 @@ static int make_request(request_queue_t *q, struct bio * bio) struct bio_list bl; struct page **behind_pages = NULL; const int rw = bio_data_dir(bio); + const int do_sync = bio_sync(bio); int do_barriers; /* @@ -835,7 +836,7 @@ static int make_request(request_queue_t *q, struct bio * bio) read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset; read_bio->bi_bdev = mirror->rdev->bdev; read_bio->bi_end_io = raid1_end_read_request; - read_bio->bi_rw = READ; + read_bio->bi_rw = READ | do_sync; read_bio->bi_private = r1_bio; generic_make_request(read_bio); @@ -906,7 +907,7 @@ static int make_request(request_queue_t *q, struct bio * bio) mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; - mbio->bi_rw = WRITE | do_barriers; + mbio->bi_rw = WRITE | do_barriers | do_sync; mbio->bi_private = r1_bio; if (behind_pages) { @@ -941,6 +942,8 @@ static int make_request(request_queue_t *q, struct bio * bio) blk_plug_device(mddev->queue); spin_unlock_irqrestore(&conf->device_lock, flags); + if (do_sync) + md_wakeup_thread(mddev->thread); #if 0 while ((bio = bio_list_pop(&bl)) != NULL) generic_make_request(bio); @@ -1263,6 +1266,11 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) sbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; sbio->bi_bdev = conf->mirrors[i].rdev->bdev; + for (j = 0; j < vcnt ; j++) + memcpy(page_address(sbio->bi_io_vec[j].bv_page), + page_address(pbio->bi_io_vec[j].bv_page), + PAGE_SIZE); + } } } @@ -1541,6 +1549,7 @@ static void raid1d(mddev_t *mddev) * We already have a nr_pending reference on these rdevs. */ int i; + const int do_sync = bio_sync(r1_bio->master_bio); clear_bit(R1BIO_BarrierRetry, &r1_bio->state); clear_bit(R1BIO_Barrier, &r1_bio->state); for (i=0; i < conf->raid_disks; i++) @@ -1561,7 +1570,7 @@ static void raid1d(mddev_t *mddev) conf->mirrors[i].rdev->data_offset; bio->bi_bdev = conf->mirrors[i].rdev->bdev; bio->bi_end_io = raid1_end_write_request; - bio->bi_rw = WRITE; + bio->bi_rw = WRITE | do_sync; bio->bi_private = r1_bio; r1_bio->bios[i] = bio; generic_make_request(bio); @@ -1593,6 +1602,7 @@ static void raid1d(mddev_t *mddev) (unsigned long long)r1_bio->sector); raid_end_bio_io(r1_bio); } else { + const int do_sync = bio_sync(r1_bio->master_bio); r1_bio->bios[r1_bio->read_disk] = mddev->ro ? IO_BLOCKED : NULL; r1_bio->read_disk = disk; @@ -1608,7 +1618,7 @@ static void raid1d(mddev_t *mddev) bio->bi_sector = r1_bio->sector + rdev->data_offset; bio->bi_bdev = rdev->bdev; bio->bi_end_io = raid1_end_read_request; - bio->bi_rw = READ; + bio->bi_rw = READ | do_sync; bio->bi_private = r1_bio; unplug = 1; generic_make_request(bio); @@ -2094,6 +2104,8 @@ static int raid1_reshape(mddev_t *mddev) return -EINVAL; } + md_allow_write(mddev); + raid_disks = mddev->raid_disks + mddev->delta_disks; if (raid_disks < conf->raid_disks) { diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index f0141910bb8..a9401c017e3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -782,6 +782,7 @@ static int make_request(request_queue_t *q, struct bio * bio) int i; int chunk_sects = conf->chunk_mask + 1; const int rw = bio_data_dir(bio); + const int do_sync = bio_sync(bio); struct bio_list bl; unsigned long flags; @@ -863,7 +864,7 @@ static int make_request(request_queue_t *q, struct bio * bio) mirror->rdev->data_offset; read_bio->bi_bdev = mirror->rdev->bdev; read_bio->bi_end_io = raid10_end_read_request; - read_bio->bi_rw = READ; + read_bio->bi_rw = READ | do_sync; read_bio->bi_private = r10_bio; generic_make_request(read_bio); @@ -909,7 +910,7 @@ static int make_request(request_queue_t *q, struct bio * bio) conf->mirrors[d].rdev->data_offset; mbio->bi_bdev = conf->mirrors[d].rdev->bdev; mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE; + mbio->bi_rw = WRITE | do_sync; mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); @@ -922,6 +923,9 @@ static int make_request(request_queue_t *q, struct bio * bio) blk_plug_device(mddev->queue); spin_unlock_irqrestore(&conf->device_lock, flags); + if (do_sync) + md_wakeup_thread(mddev->thread); + return 0; } @@ -1563,6 +1567,7 @@ static void raid10d(mddev_t *mddev) (unsigned long long)r10_bio->sector); raid_end_bio_io(r10_bio); } else { + const int do_sync = bio_sync(r10_bio->master_bio); rdev = conf->mirrors[mirror].rdev; if (printk_ratelimit()) printk(KERN_ERR "raid10: %s: redirecting sector %llu to" @@ -1574,7 +1579,7 @@ static void raid10d(mddev_t *mddev) bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr + rdev->data_offset; bio->bi_bdev = rdev->bdev; - bio->bi_rw = READ; + bio->bi_rw = READ | do_sync; bio->bi_private = r10_bio; bio->bi_end_io = raid10_end_read_request; unplug = 1; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index be008f034ad..467c16982d0 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -405,6 +405,8 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) if (newsize <= conf->pool_size) return 0; /* never bother to shrink */ + md_allow_write(conf->mddev); + /* Step 1 */ sc = kmem_cache_create(conf->cache_name[1-conf->active_name], sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev), @@ -2678,7 +2680,7 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) mdk_rdev_t *rdev; if (!in_chunk_boundary(mddev, raid_bio)) { - printk("chunk_aligned_read : non aligned\n"); + PRINTK("chunk_aligned_read : non aligned\n"); return 0; } /* @@ -3250,6 +3252,7 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) else break; } + md_allow_write(mddev); while (new > conf->max_nr_stripes) { if (grow_one_stripe(conf)) conf->max_nr_stripes++; diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index 8eaa88fd8b9..9a8dd8764c9 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> +#include <linux/jiffies.h> #include <media/ir-common.h> /* -------------------------------------------------------------------------- */ diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index ebf4dc5190f..76e9c36597e 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -605,7 +605,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { &utype, sizeof utype }, { priv->ule_skb->data, priv->ule_skb->len - 4 } }; - unsigned long ule_crc = ~0L, expected_crc; + u32 ule_crc = ~0L, expected_crc; if (priv->ule_dbit) { /* Set D-bit for CRC32 verification, * if it was set originally. */ @@ -618,7 +618,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) *((u8 *)priv->ule_skb->tail - 2) << 8 | *((u8 *)priv->ule_skb->tail - 1); if (ule_crc != expected_crc) { - printk(KERN_WARNING "%lu: CRC32 check FAILED: %#lx / %#lx, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", + printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); #ifdef ULE_DEBUG diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index d48622e76b1..badc468170e 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -90,9 +90,11 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle); for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) { - deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom); if (haupp_rc_keys[i].data == data && haupp_rc_keys[i].custom == custom) { + + deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom); + *event = haupp_rc_keys[i].event; *state = REMOTE_KEY_PRESSED; if (st->old_toggle == toggle) { diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 5da66178006..23aa75a27c1 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -515,7 +515,7 @@ static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000 fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2; fchan.vit_hrch = 0; fchan.vit_select_hp = 1; - dib3000mc_set_channel_cfg(state, &fchan, 7); + dib3000mc_set_channel_cfg(state, &fchan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 29a11c1db1b..57357db31b8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -668,7 +668,7 @@ config VIDEO_M32R_AR_M64278 config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" - depends on I2C && VIDEO_V4L2 + depends on PCI && I2C && VIDEO_V4L2 select VIDEO_OV7670 ---help--- This is a video4linux2 driver for the Marvell 88ALP01 integrated diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 3c8e4742dcc..ab8f970760f 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -4050,8 +4050,8 @@ static int __devinit bttv_probe(struct pci_dev *dev, (unsigned long long)pci_resource_start(dev,0)); schedule(); - btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000); - if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) { + btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); + if (NULL == btv->bt848_mmio) { printk("bttv%d: ioremap() failed\n", btv->c.nr); result = -EIO; goto fail1; diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index e347c7ebc98..3083c8075d1 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -2166,7 +2166,7 @@ static void cafe_pci_remove(struct pci_dev *pdev) struct cafe_camera *cam = cafe_find_by_pdev(pdev); if (cam == NULL) { - cam_warn(cam, "pci_remove on unknown pdev %p\n", pdev); + printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); return; } mutex_lock(&cam->s_mutex); diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c index 28dc6a1a1e4..d8e929863a8 100644 --- a/drivers/media/video/cpia2/cpia2_usb.c +++ b/drivers/media/video/cpia2/cpia2_usb.c @@ -640,6 +640,10 @@ static int submit_urbs(struct camera_data *cam) cam->sbuf[i].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); if (!cam->sbuf[i].data) { + while (--i >= 0) { + kfree(cam->sbuf[i].data); + cam->sbuf[i].data = NULL; + } return -ENOMEM; } } diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 657e0b96914..2f5ca71e026 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -742,7 +742,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, if (old == NULL || old->width != new->width || old->height != new->height || old->video_encoding != new->video_encoding) { - int is_scaling; u16 w = new->width; u16 h = new->height; @@ -752,20 +751,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, } err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); if (err) return err; + } + if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) { /* Adjust temporal filter if necessary. The problem with the temporal filter is that it works well with full resolution capturing, but not when the capture window is scaled (the filter introduces - a ghosting effect). So if the capture window changed, and there is - no updated filter value, then the filter is set depending on whether - the new window is full resolution or not. + a ghosting effect). So if the capture window is scaled, then + force the filter to 0. - For full resolution a setting of 8 really improves the video + For full resolution the filter really improves the video quality, especially if the original video quality is suboptimal. */ - is_scaling = new->width != 720 || new->height != (new->is_50hz ? 576 : 480); - if (old && old->video_temporal_filter == temporal) { - temporal = is_scaling ? 0 : 8; - } + temporal = 0; } if (old == NULL || old->stream_type != new->stream_type) { @@ -866,6 +863,7 @@ invalid: void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) { int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + int temporal = p->video_temporal_filter; /* Stream */ printk(KERN_INFO "%s: Stream: %s\n", @@ -922,10 +920,13 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), p->video_spatial_filter); + if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) { + temporal = 0; + } printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), - p->video_temporal_filter); + temporal); printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index f85f2084324..ced13febed8 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -128,7 +128,14 @@ void cx25840_vbi_setup(struct i2c_client *client) uv_lpf=1; src_decimation=0x21f; - if (std == V4L2_STD_PAL_M) { + 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; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index c791708b133..434b78ab37d 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1632,7 +1632,7 @@ const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); /* ----------------------------------------------------------------------- */ /* some leadtek specific stuff */ -static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) +static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) { /* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on * any others. diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 453af5e943f..18997361c75 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -633,12 +633,12 @@ int cx88_reset(struct cx88_core *core) static unsigned int inline norm_swidth(struct cx88_tvnorm *norm) { - return (norm->id & V4L2_STD_625_50) ? 922 : 754; + return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; } static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm) { - return (norm->id & V4L2_STD_625_50) ? 186 : 135; + return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186; } static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm) @@ -648,24 +648,33 @@ static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm) static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm) { - static const unsigned int ntsc = 28636360; - static const unsigned int pal = 35468950; - static const unsigned int palm = 28604892; - if (norm->id & V4L2_STD_PAL_M) - return palm; + return 28604892; // 3.575611 MHz + + if (norm->id & (V4L2_STD_PAL_Nc)) + return 28656448; // 3.582056 MHz + + if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants + return 28636360; // 3.57954545 MHz +/- 10 Hz - return (norm->id & V4L2_STD_625_50) ? pal : ntsc; + /* SECAM have also different sub carrier for chroma, + but step_db and step_dr, at cx88_set_tvnorm already handles that. + + The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N + */ + + return 35468950; // 4.43361875 MHz +/- 5 Hz } static unsigned int inline norm_htotal(struct cx88_tvnorm *norm) { - /* Should always be Line Draw Time / (4*FSC) */ - if (norm->id & V4L2_STD_PAL_M) - return 909; + unsigned int fsc4=norm_fsc8(norm)/2; - return (norm->id & V4L2_STD_625_50) ? 1135 : 910; + /* returns 4*FSC / vtotal / frames per seconds */ + return (norm->id & V4L2_STD_625_50) ? + ((fsc4+312)/625+12)/25 : + ((fsc4+262)/525*1001+15000)/30000; } static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm) @@ -692,7 +701,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig value &= 0x3fe; cx_write(MO_HDELAY_EVEN, value); cx_write(MO_HDELAY_ODD, value); - dprintk(1,"set_scale: hdelay 0x%04x\n", value); + dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth); value = (swidth * 4096 / width) - 4096; cx_write(MO_HSCALE_EVEN, value); diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 3482e0114d4..2bd84d351a1 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -38,6 +38,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/errno.h> +#include <linux/freezer.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mm.h> @@ -961,6 +962,7 @@ int cx88_audio_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; + try_to_freeze(); /* just monitor the audio status for now ... */ memset(&t, 0, sizeof(t)); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 7054e941f1d..a9575ad8ca2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -91,7 +91,7 @@ struct cx88_tvnorm { static unsigned int inline norm_maxw(struct cx88_tvnorm *norm) { - return (norm->id & V4L2_STD_625_50) ? 768 : 640; + return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 2a461dde480..36e72c207a8 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1674,9 +1674,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); - udelay(2500); + msleep(3); em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); - udelay(2500); + msleep(3); } video_mux(dev, 0); diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c index c1a377f797d..b6cd21e6dab 100644 --- a/drivers/media/video/ks0127.c +++ b/drivers/media/video/ks0127.c @@ -712,13 +712,13 @@ static int ks0127_command(struct i2c_client *client, *iarg = 0; status = ks0127_read(ks, KS_STAT); if (!(status & 0x20)) /* NOVID not set */ - *iarg = (*iarg & DECODER_STATUS_GOOD); + *iarg = (*iarg | DECODER_STATUS_GOOD); if ((status & 0x01)) /* CLOCK set */ - *iarg = (*iarg & DECODER_STATUS_COLOR); + *iarg = (*iarg | DECODER_STATUS_COLOR); if ((status & 0x08)) /* PALDET set */ - *iarg = (*iarg & DECODER_STATUS_PAL); + *iarg = (*iarg | DECODER_STATUS_PAL); else - *iarg = (*iarg & DECODER_STATUS_NTSC); + *iarg = (*iarg | DECODER_STATUS_NTSC); break; //Catch any unknown command diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index b083338823d..616a35da191 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -923,7 +923,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, struct video_picture *p = arg; if (p->depth != 16) return -EINVAL; - if (p->palette != VIDEO_PALETTE_YUV422) + if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV) return -EINVAL; mutex_lock(&meye.lock); sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, @@ -978,7 +978,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (vm->frame >= gbuffers || vm->frame < 0) return -EINVAL; - if (vm->format != VIDEO_PALETTE_YUV422) + if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV) return -EINVAL; if (vm->height * vm->width * 2 > gbufsize) return -EINVAL; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index e1b56dc13c3..2fb9fe6a1ae 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -633,10 +633,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (((rt->input >> (4 + i * 4)) & 0xf) == 0) extern_input = 0; } - if (extern_input) - state->mode = MSP_MODE_EXTERN; - else - state->mode = MSP_MODE_AM_DETECT; + state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; msp_set_scart(client, sc_in, 0); msp_set_scart(client, sc1_out, 1); msp_set_scart(client, sc2_out, 2); @@ -951,7 +949,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) if (thread_func) { state->kthread = kthread_run(thread_func, client, "msp34xx"); - if (state->kthread == NULL) + if (IS_ERR(state->kthread)) v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 4c7f85b566a..e1821eb82fb 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -483,7 +483,6 @@ int msp3400c_thread(void *data) /* no carrier scan, just unmute */ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); state->scan_in_progress = 0; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; msp_set_audio(client); continue; } @@ -851,12 +850,15 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) source = 1; /* stereo or A|B */ matrix = 0x20; break; - case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1: - default: source = 3; /* stereo or A */ matrix = 0x00; break; + case V4L2_TUNER_MODE_STEREO: + default: + source = 3; /* stereo or A */ + matrix = 0x20; + break; } if (in == MSP_DSP_IN_TUNER) @@ -1030,6 +1032,9 @@ static int msp34xxg_detect_stereo(struct i2c_client *client) int is_stereo = status & 0x40; int oldrx = state->rxsubchans; + if (state->mode == MSP_MODE_EXTERN) + return 0; + state->rxsubchans = 0; if (is_stereo) state->rxsubchans = V4L2_TUNER_SUB_STEREO; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 4dead84aff4..ae984bbe36b 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2570,6 +2570,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .gpiomask = 1 << 21, .inputs = {{ .name = name_tv, .vmux = 1, @@ -2578,15 +2579,20 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_comp1, .vmux = 3, - .amux = LINE1, + .amux = LINE2, /* unconfirmed, taken from Philips driver */ + },{ + .name = name_comp2, + .vmux = 0, /* untested, Composite over S-Video */ + .amux = LINE2, },{ .name = name_svideo, - .vmux = 0, - .amux = LINE1, + .vmux = 8, + .amux = LINE2, }}, .radio = { .name = name_radio, - .amux = LINE1, + .amux = TV, + .gpio = 0x0200000, }, }, [SAA7134_BOARD_CINERGY250PCI] = { diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index fa833987909..c33f6a69a24 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -50,9 +50,9 @@ static unsigned int antenna_pwr = 0; module_param(antenna_pwr, int, 0444); MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); -static int use_frontent = 0; -module_param(use_frontent, int, 0644); -MODULE_PARM_DESC(use_frontent,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); +static int use_frontend = 0; +module_param(use_frontend, int, 0644); +MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); /* ------------------------------------------------------------------ */ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) @@ -1303,7 +1303,7 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_FLYDVB_TRIO: - if(! use_frontent) { //terrestrial + if(! use_frontend) { //terrestrial dev->dvb.frontend = dvb_attach(tda10046_attach, &lifeview_trio_config, &dev->i2c_adap); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 705daaa2a4f..ee4a493032d 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -267,6 +267,10 @@ static int tuner_fixup_std(struct tuner *t) { if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { + case '6': + tuner_dbg ("insmod fixup: PAL => PAL-60\n"); + t->std = V4L2_STD_PAL_60; + break; case 'b': case 'B': case 'g': diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 2624e3f7dd2..4e7c1fa668d 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -184,7 +184,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Thompson DTT757"}, /* 80-89 */ { TUNER_ABSENT, "Philips FQ1216LME MK3"}, - { TUNER_ABSENT, "LG TAPC G701D"}, + { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h index baab9c081b5..17ace394d98 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.h +++ b/drivers/media/video/usbvideo/quickcam_messenger.h @@ -35,27 +35,13 @@ struct rgb { }; struct bayL0 { -#ifdef __BIG_ENDIAN - u8 r; - u8 g; -#elif __LITTLE_ENDIAN u8 g; u8 r; -#else -#error not byte order defined -#endif }; struct bayL1 { -#ifdef __BIG_ENDIAN - u8 g; - u8 b; -#elif __LITTLE_ENDIAN u8 b; u8 g; -#else -#error not byte order defined -#endif }; struct cam_size { diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 134eb9865df..a40e5838515 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -39,8 +39,8 @@ struct usbvision_device_data_st usbvision_device_data[] = { {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, - {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, - {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, + {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, + {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, @@ -71,10 +71,10 @@ struct usbvision_device_data_st usbvision_device_data[] = { {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, - {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, + {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, - {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, + {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, @@ -86,7 +86,7 @@ struct usbvision_device_data_st usbvision_device_data[] = { {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, - {0x2400, 0x4200, -1, CODEC_SAA7111, 3, VIDEO_MODE_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {0x2400, 0x4200, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, {} /* Terminating entry */ }; @@ -148,7 +148,6 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ - { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ { } /* Terminating entry */ diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 797b97baf9e..a807d971e27 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -118,7 +118,7 @@ static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision); * This is used when initializing the contents of the area. */ -void *usbvision_rvmalloc(unsigned long size) +static void *usbvision_rvmalloc(unsigned long size) { void *mem; unsigned long adr; @@ -181,7 +181,7 @@ static void usbvision_hexdump(const unsigned char *data, int len) /******************************** * scratch ring buffer handling ********************************/ -int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */ +static int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */ { int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr; if (len < 0) { @@ -194,7 +194,7 @@ int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of /* This returns the free space left in the buffer */ -int scratch_free(struct usb_usbvision *usbvision) +static int scratch_free(struct usb_usbvision *usbvision) { int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr; if (free <= 0) { @@ -211,7 +211,8 @@ int scratch_free(struct usb_usbvision *usbvision) /* This puts data into the buffer */ -int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, int len) +static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, + int len) { int len_part; @@ -237,7 +238,7 @@ int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, int len) } /* This marks the write_ptr as position of new frame header */ -void scratch_mark_header(struct usb_usbvision *usbvision) +static void scratch_mark_header(struct usb_usbvision *usbvision) { PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr); @@ -248,7 +249,8 @@ void scratch_mark_header(struct usb_usbvision *usbvision) } /* This gets data from the buffer at the given "ptr" position */ -int scratch_get_extra(struct usb_usbvision *usbvision, unsigned char *data, int *ptr, int len) +static int scratch_get_extra(struct usb_usbvision *usbvision, + unsigned char *data, int *ptr, int len) { int len_part; if (*ptr + len < scratch_buf_size) { @@ -274,7 +276,8 @@ int scratch_get_extra(struct usb_usbvision *usbvision, unsigned char *data, int /* This sets the scratch extra read pointer */ -void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, int len) +static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, + int len) { *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size; @@ -283,7 +286,7 @@ void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, int len) /*This increments the scratch extra read pointer */ -void scratch_inc_extra_ptr(int *ptr, int len) +static void scratch_inc_extra_ptr(int *ptr, int len) { *ptr = (*ptr + len) % scratch_buf_size; @@ -292,7 +295,8 @@ void scratch_inc_extra_ptr(int *ptr, int len) /* This gets data from the buffer */ -int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, int len) +static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, + int len) { int len_part; if (usbvision->scratch_read_ptr + len < scratch_buf_size) { @@ -318,7 +322,8 @@ int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, int len) /* This sets read pointer to next header and returns it */ -int scratch_get_header(struct usb_usbvision *usbvision,struct usbvision_frame_header *header) +static int scratch_get_header(struct usb_usbvision *usbvision, + struct usbvision_frame_header *header) { int errCode = 0; @@ -346,7 +351,7 @@ int scratch_get_header(struct usb_usbvision *usbvision,struct usbvision_frame_he /*This removes len bytes of old data from the buffer */ -void scratch_rm_old(struct usb_usbvision *usbvision, int len) +static void scratch_rm_old(struct usb_usbvision *usbvision, int len) { usbvision->scratch_read_ptr += len; @@ -356,7 +361,7 @@ void scratch_rm_old(struct usb_usbvision *usbvision, int len) /*This resets the buffer - kills all data in it too */ -void scratch_reset(struct usb_usbvision *usbvision) +static void scratch_reset(struct usb_usbvision *usbvision) { PDEBUG(DBG_SCRATCH, "\n"); @@ -369,7 +374,7 @@ void scratch_reset(struct usb_usbvision *usbvision) int usbvision_scratch_alloc(struct usb_usbvision *usbvision) { - usbvision->scratch = vmalloc(scratch_buf_size); + usbvision->scratch = vmalloc_32(scratch_buf_size); scratch_reset(usbvision); if(usbvision->scratch == NULL) { err("%s: unable to allocate %d bytes for scratch", @@ -399,8 +404,8 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision) * 1: Draw a colored grid * */ -void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, - int pmode) +static void usbvision_testpattern(struct usb_usbvision *usbvision, + int fullframe, int pmode) { static const char proc[] = "usbvision_testpattern"; struct usbvision_frame *frame; @@ -480,7 +485,7 @@ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, int usbvision_decompress_alloc(struct usb_usbvision *usbvision) { int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2; - usbvision->IntraFrameBuffer = vmalloc(IFB_size); + usbvision->IntraFrameBuffer = vmalloc_32(IFB_size); if (usbvision->IntraFrameBuffer == NULL) { err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size); return -ENOMEM; @@ -2199,6 +2204,7 @@ int usbvision_power_on(struct usb_usbvision *usbvision) usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN); usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN | USBVISION_RES2); + usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN | USBVISION_PWR_VID); errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, @@ -2305,7 +2311,7 @@ int usbvision_restart_isoc(struct usb_usbvision *usbvision) usbvision->Vin_Reg2_Preset)) < 0) return ret; /* TODO: schedule timeout */ - while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) && 0x01) != 1); + while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1); return 0; } @@ -2346,40 +2352,6 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format) return USBVISION_IS_OPERATIONAL(usbvision); } - -int usbvision_sbuf_alloc(struct usb_usbvision *usbvision) -{ - int i, errCode = 0; - const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE; - - /* Clean pointers so we know if we allocated something */ - for (i = 0; i < USBVISION_NUMSBUF; i++) - usbvision->sbuf[i].data = NULL; - - for (i = 0; i < USBVISION_NUMSBUF; i++) { - usbvision->sbuf[i].data = kzalloc(sb_size, GFP_KERNEL); - if (usbvision->sbuf[i].data == NULL) { - err("%s: unable to allocate %d bytes for sbuf", __FUNCTION__, sb_size); - errCode = -ENOMEM; - break; - } - } - return errCode; -} - - -void usbvision_sbuf_free(struct usb_usbvision *usbvision) -{ - int i; - - for (i = 0; i < USBVISION_NUMSBUF; i++) { - if (usbvision->sbuf[i].data != NULL) { - kfree(usbvision->sbuf[i].data); - usbvision->sbuf[i].data = NULL; - } - } -} - /* * usbvision_init_isoc() * @@ -2388,6 +2360,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) { struct usb_device *dev = usbvision->dev; int bufIdx, errCode, regValue; + const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE; if (!USBVISION_IS_OPERATIONAL(usbvision)) return -EFAULT; @@ -2423,6 +2396,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) return -ENOMEM; } usbvision->sbuf[bufIdx].urb = urb; + usbvision->sbuf[bufIdx].data = usb_buffer_alloc(usbvision->dev, sb_size, GFP_KERNEL,&urb->transfer_dma); urb->dev = dev; urb->context = usbvision; urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp); @@ -2464,6 +2438,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) void usbvision_stop_isoc(struct usb_usbvision *usbvision) { int bufIdx, errCode, regValue; + const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE; if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL)) return; @@ -2471,6 +2446,12 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision) /* Unschedule all of the iso td's */ for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) { usb_kill_urb(usbvision->sbuf[bufIdx].urb); + if (usbvision->sbuf[bufIdx].data){ + usb_buffer_free(usbvision->dev, + sb_size, + usbvision->sbuf[bufIdx].data, + usbvision->sbuf[bufIdx].urb->transfer_dma); + } usb_free_urb(usbvision->sbuf[bufIdx].urb); usbvision->sbuf[bufIdx].urb = NULL; } diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 0f3fba7ea6f..858252c1508 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -58,7 +58,6 @@ static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, static inline int try_write_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) { - struct i2c_algo_usb_data *adap = i2c_adap->algo_data; void *data; int i, ret = -1; char buf[4]; @@ -69,10 +68,10 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, ret = (usbvision_i2c_write(data, addr, buf, 1)); if (ret == 1) break; /* success! */ - udelay(5 /*adap->udelay */ ); + udelay(5); if (i == retries) /* no success */ break; - udelay(adap->udelay); + udelay(10); } if (i) { PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); @@ -84,7 +83,6 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, static inline int try_read_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) { - struct i2c_algo_usb_data *adap = i2c_adap->algo_data; void *data; int i, ret = -1; char buf[4]; @@ -94,10 +92,10 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, ret = (usbvision_i2c_read(data, addr, buf, 1)); if (ret == 1) break; /* success! */ - udelay(5 /*adap->udelay */ ); + udelay(5); if (i == retries) /* no success */ break; - udelay(adap->udelay); + udelay(10); } if (i) { PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); @@ -213,7 +211,7 @@ static struct i2c_algorithm i2c_usb_algo = { /* * registering functions to load algorithms at runtime */ -int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) +static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) { PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); PDEBUG(DBG_ALGO, "ALGO debugging is enabled [i2c]"); @@ -248,15 +246,12 @@ int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) /* usbvision specific I2C functions */ /* ----------------------------------------------------------------------- */ static struct i2c_adapter i2c_adap_template; -static struct i2c_algo_usb_data i2c_algo_template; static struct i2c_client i2c_client_template; int usbvision_init_i2c(struct usb_usbvision *usbvision) { memcpy(&usbvision->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); - memcpy(&usbvision->i2c_algo, &i2c_algo_template, - sizeof(struct i2c_algo_usb_data)); memcpy(&usbvision->i2c_client, &i2c_client_template, sizeof(struct i2c_client)); @@ -266,9 +261,7 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) i2c_set_adapdata(&usbvision->i2c_adap, usbvision); i2c_set_clientdata(&usbvision->i2c_client, usbvision); - i2c_set_algo_usb_data(&usbvision->i2c_algo, usbvision); - usbvision->i2c_adap.algo_data = &usbvision->i2c_algo; usbvision->i2c_client.adapter = &usbvision->i2c_adap; if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { @@ -297,7 +290,6 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg) { - BUG_ON(NULL == usbvision->i2c_adap.algo_data); i2c_clients_command(&usbvision->i2c_adap, cmd, arg); } @@ -327,6 +319,9 @@ static int attach_inform(struct i2c_client *client) case 0x4a: PDEBUG(DBG_I2C,"attach_inform: saa7113 detected."); break; + case 0x48: + PDEBUG(DBG_I2C,"attach_inform: saa7111 detected."); + break; case 0xa0: PDEBUG(DBG_I2C,"attach_inform: eeprom detected."); break; @@ -531,21 +526,10 @@ static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, return rdcount; } -static struct i2c_algo_usb_data i2c_algo_template = { - .data = NULL, - .inb = usbvision_i2c_read, - .outb = usbvision_i2c_write, - .udelay = 10, - .mdelay = 10, - .timeout = 100, -}; - static struct i2c_adapter i2c_adap_template = { .owner = THIS_MODULE, .name = "usbvision", .id = I2C_HW_B_BT848, /* FIXME */ - .algo = NULL, - .algo_data = NULL, .client_register = attach_inform, .client_unregister = detach_inform, #ifdef I2C_ADAP_CLASS_TV_ANALOG @@ -559,9 +543,6 @@ static struct i2c_client i2c_client_template = { .name = "usbvision internal", }; -EXPORT_SYMBOL(usbvision_i2c_usb_add_bus); -EXPORT_SYMBOL(usbvision_i2c_usb_del_bus); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 864446c012e..7243337b771 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -204,7 +204,7 @@ MODULE_ALIAS(DRIVER_ALIAS); static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) { - struct video_device *vdev = to_video_device(cd); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); return video_get_drvdata(vdev); } @@ -214,81 +214,85 @@ static ssize_t show_version(struct class_device *cd, char *buf) } static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); -static ssize_t show_model(struct class_device *class_dev, char *buf) +static ssize_t show_model(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); } static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_hue(struct class_device *class_dev, char *buf) +static ssize_t show_hue(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_HUE; ctrl.value = 0; - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + if(usbvision->user) + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value >> 8); } static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_contrast(struct class_device *class_dev, char *buf) +static ssize_t show_contrast(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_CONTRAST; ctrl.value = 0; - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + if(usbvision->user) + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value >> 8); } static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_brightness(struct class_device *class_dev, char *buf) +static ssize_t show_brightness(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_BRIGHTNESS; ctrl.value = 0; - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + if(usbvision->user) + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value >> 8); } static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *class_dev, char *buf) +static ssize_t show_saturation(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_SATURATION; ctrl.value = 0; - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + if(usbvision->user) + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value >> 8); } static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_streaming(struct class_device *class_dev, char *buf) +static ssize_t show_streaming(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); -static ssize_t show_compression(struct class_device *class_dev, char *buf) +static ssize_t show_compression(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); } static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); -static ssize_t show_device_bridge(struct class_device *class_dev, char *buf) +static ssize_t show_device_bridge(struct class_device *cd, char *buf) { - struct video_device *vdev = to_video_device(class_dev); + struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } @@ -297,31 +301,71 @@ static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { int res; - if (vdev) { - res=video_device_create_file(vdev, &class_device_attr_version); - res=video_device_create_file(vdev, &class_device_attr_model); - res=video_device_create_file(vdev, &class_device_attr_hue); - res=video_device_create_file(vdev, &class_device_attr_contrast); - res=video_device_create_file(vdev, &class_device_attr_brightness); - res=video_device_create_file(vdev, &class_device_attr_saturation); - res=video_device_create_file(vdev, &class_device_attr_streaming); - res=video_device_create_file(vdev, &class_device_attr_compression); - res=video_device_create_file(vdev, &class_device_attr_bridge); - } + if (!vdev) + return; + do { + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_version); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_model); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_hue); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_contrast); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_brightness); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_saturation); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_streaming); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_compression); + if (res<0) + break; + res=class_device_create_file(&vdev->class_dev, + &class_device_attr_bridge); + if (res>=0) + return; + } while (0); + + err("%s error: %d\n", __FUNCTION__, res); } static void usbvision_remove_sysfs(struct video_device *vdev) { if (vdev) { - video_device_remove_file(vdev, &class_device_attr_version); - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_hue); - video_device_remove_file(vdev, &class_device_attr_contrast); - video_device_remove_file(vdev, &class_device_attr_brightness); - video_device_remove_file(vdev, &class_device_attr_saturation); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_compression); - video_device_remove_file(vdev, &class_device_attr_bridge); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_version); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_model); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_hue); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_contrast); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_brightness); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_saturation); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_streaming); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_compression); + class_device_remove_file(&vdev->class_dev, + &class_device_attr_bridge); } } @@ -353,20 +397,15 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) if(!errCode) { /* Allocate memory for the scratch ring buffer */ errCode = usbvision_scratch_alloc(usbvision); - if(!errCode) { - /* Allocate memory for the USB S buffers */ - errCode = usbvision_sbuf_alloc(usbvision); - if ((!errCode) && (usbvision->isocMode==ISOC_MODE_COMPRESS)) { - /* Allocate intermediate decompression buffers only if needed */ - errCode = usbvision_decompress_alloc(usbvision); - } + if ((!errCode) && (isocMode==ISOC_MODE_COMPRESS)) { + /* Allocate intermediate decompression buffers only if needed */ + errCode = usbvision_decompress_alloc(usbvision); } } if (errCode) { /* Deallocate all buffers if trouble */ usbvision_frames_free(usbvision); usbvision_scratch_free(usbvision); - usbvision_sbuf_free(usbvision); usbvision_decompress_free(usbvision); } } @@ -437,9 +476,8 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) usbvision_stop_isoc(usbvision); usbvision_decompress_free(usbvision); - usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); + usbvision_frames_free(usbvision); usbvision_scratch_free(usbvision); - usbvision_sbuf_free(usbvision); usbvision->user--; @@ -1042,7 +1080,6 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, int noblock = file->f_flags & O_NONBLOCK; unsigned long lock_flags; - int frmx = -1; int ret,i; struct usbvision_frame *frame; @@ -1117,7 +1154,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, frame->bytes_read = 0; /* Mark it as available to be used again. */ - usbvision->frame[frmx].grabstate = FrameState_Unused; + frame->grabstate = FrameState_Unused; /* } */ return count; @@ -1884,7 +1921,7 @@ static struct usb_driver usbvision_driver = { * This procedure preprocesses CustomDevice parameter if any * */ -void customdevice_process(void) +static void customdevice_process(void) { usbvision_device_data[0]=usbvision_device_data[1]; usbvision_table[0]=usbvision_table[1]; @@ -1939,22 +1976,22 @@ void customdevice_process(void) { case 'P': PDEBUG(DBG_PROBE, "VideoNorm=PAL"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; + usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; break; case 'S': PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_SECAM; + usbvision_device_data[0].VideoNorm=V4L2_STD_SECAM; break; case 'N': PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_NTSC; + usbvision_device_data[0].VideoNorm=V4L2_STD_NTSC; break; default: PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; + usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; break; } goto2next(parse); diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 0e7e3d653ca..e2bcaba9387 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -219,18 +219,6 @@ enum { ((udevice)->last_error == 0) && \ (!(udevice)->remove_pending)) -/* I2C structures */ -struct i2c_algo_usb_data { - void *data; /* private data for lowlevel routines */ - int (*inb) (void *data, unsigned char addr, char *buf, short len); - int (*outb) (void *data, unsigned char addr, char *buf, short len); - - /* local settings */ - int udelay; - int mdelay; - int timeout; -}; - #define I2C_USB_ADAP_MAX 16 /* ----------------------------------------------------------------- */ @@ -383,7 +371,6 @@ struct usb_usbvision { /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; - struct i2c_algo_usb_data i2c_algo; struct i2c_client i2c_client; struct urb *ctrlUrb; @@ -489,19 +476,8 @@ struct usb_usbvision { /* i2c-algo-usb declaration */ /* --------------------------------------------------------------- */ -int usbvision_i2c_usb_add_bus(struct i2c_adapter *); int usbvision_i2c_usb_del_bus(struct i2c_adapter *); -static inline void *i2c_get_algo_usb_data (struct i2c_algo_usb_data *dev) -{ - return dev->data; -} - -static inline void i2c_set_algo_usb_data (struct i2c_algo_usb_data *dev, void *data) -{ - dev->data = data; -} - /* ----------------------------------------------------------------------- */ /* usbvision specific I2C functions */ @@ -510,7 +486,6 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision); void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); /* defined in usbvision-core.c */ -void *usbvision_rvmalloc(unsigned long size); void usbvision_rvfree(void *mem, unsigned long size); int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, @@ -520,8 +495,6 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision); void usbvision_frames_free(struct usb_usbvision *usbvision); int usbvision_scratch_alloc(struct usb_usbvision *usbvision); void usbvision_scratch_free(struct usb_usbvision *usbvision); -int usbvision_sbuf_alloc(struct usb_usbvision *usbvision); -void usbvision_sbuf_free(struct usb_usbvision *usbvision); int usbvision_decompress_alloc(struct usb_usbvision *usbvision); void usbvision_decompress_free(struct usb_usbvision *usbvision); diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 752c82c37f5..b87d571e046 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -90,8 +90,15 @@ MODULE_LICENSE("GPL"); char *v4l2_norm_to_name(v4l2_std_id id) { char *name; + u32 myid = id; - switch (id) { + /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle + 64 bit comparations. So, on that architecture, with some gcc variants, + compilation fails. Currently, the max value is 30bit wide. + */ + BUG_ON(myid != id); + + switch (myid) { case V4L2_STD_PAL: name="PAL"; break; case V4L2_STD_PAL_BG: diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index f429f49901b..6504a586684 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -700,6 +700,7 @@ videobuf_qbuf(struct videobuf_queue *q, goto done; } if (buf->state == STATE_QUEUED || + buf->state == STATE_PREPARED || buf->state == STATE_ACTIVE) { dprintk(1,"qbuf: buffer is already queued or active.\n"); goto done; @@ -1229,7 +1230,7 @@ videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, vaddr,vma->vm_start,vma->vm_end); if (vaddr > vma->vm_end) return NOPAGE_SIGBUS; - page = alloc_page(GFP_USER); + page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) return NOPAGE_OOM; clear_user_page(page_address(page), vaddr, page); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 474ddb77964..d4cf5566673 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -270,10 +270,15 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, char *p,*s,*basep; struct page *pg; u8 chr,r,g,b,color; + unsigned long flags; + spinlock_t spinlock; + + spin_lock_init(&spinlock); /* Get first addr pointed to pixel position */ oldpg=get_addr_pos(pos,pages,to_addr); pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); + spin_lock_irqsave(&spinlock,flags); basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; /* We will just duplicate the second pixel at the packet */ @@ -376,6 +381,8 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, end: kunmap_atomic(basep, KM_BOUNCE_READ); + spin_unlock_irqrestore(&spinlock,flags); + } static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) { @@ -535,9 +542,9 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q) dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); - if (dma_q->kthread == NULL) { + if (IS_ERR(dma_q->kthread)) { printk(KERN_ERR "vivi: kernel_thread() failed\n"); - return -EINVAL; + return PTR_ERR(dma_q->kthread); } dprintk(1,"returning from %s\n",__FUNCTION__); return 0; @@ -1363,7 +1370,9 @@ static void __exit vivi_exit(void) struct vivi_dev *h; struct list_head *list; - list_for_each(list,&vivi_devlist) { + while (!list_empty(&vivi_devlist)) { + list = vivi_devlist.next; + list_del(list); h = list_entry(list, struct vivi_dev, vivi_devlist); kfree (h); } diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 4bdc886abc4..8d14f308f17 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -789,7 +789,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file, case VIDIOCSPICT: { struct video_picture *vpic = arg; - if (vpic->depth != 16 || vpic->palette != VIDEO_PALETTE_YUV422) + if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV)) return -EINVAL; cam->brightness = vpic->brightness >> 8; diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index ddce2fb8342..9f403af7b04 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -1827,8 +1827,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) int err = 0; /* Work around to avoid FP arithmetics */ - #define __SC(x) ((x) << 10) - #define __UNSC(x) ((x) >> 10) + #define SC(x) ((x) << 10) + #define UNSC(x) ((x) >> 10) /* Make sure we are using a supported resolution */ if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, @@ -1836,15 +1836,15 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) goto error; /* Scaling factors */ - fw = __SC(win.width) / cam->maxwidth; - fh = __SC(win.height) / cam->maxheight; + fw = SC(win.width) / cam->maxwidth; + fh = SC(win.height) / cam->maxheight; /* Set up the width and height values used by the chip */ if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { cam->vpp_flag |= VPP_UPSCALE; /* Calculate largest w,h mantaining the same w/h ratio */ - w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; - h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; + w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh; + h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight; if (w < cam->minwidth) /* just in case */ w = cam->minwidth; if (h < cam->minheight) /* just in case */ @@ -1861,8 +1861,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) /* Calculate cropped area manteining the right w/h ratio */ if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { - cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; - ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; + cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh; + ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight; } else { cw = w; ch = h; @@ -1901,8 +1901,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) /* We have to scale win.x and win.y offsets */ if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) || (cam->vpp_flag & VPP_UPSCALE) ) { - ax = __SC(win.x)/fw; - ay = __SC(win.y)/fh; + ax = SC(win.x)/fw; + ay = SC(win.y)/fh; } else { ax = win.x; ay = win.y; @@ -1917,8 +1917,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) /* Adjust win.x, win.y */ if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) || (cam->vpp_flag & VPP_UPSCALE) ) { - win.x = __UNSC(ax*fw); - win.y = __UNSC(ay*fh); + win.x = UNSC(ax*fw); + win.y = UNSC(ay*fh); } else { win.x = ax; win.y = ay; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index 168e431d7c7..b0752767ee4 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -429,7 +429,7 @@ zr36057_set_vfe (struct zoran *zr, reg |= (HorDcm << ZR36057_VFESPFR_HorDcm); reg |= (VerDcm << ZR36057_VFESPFR_VerDcm); reg |= (DispMode << ZR36057_VFESPFR_DispMode); - if (format->palette != VIDEO_PALETTE_YUV422) + if (format->palette != VIDEO_PALETTE_YUV422 && format->palette != VIDEO_PALETTE_YUYV) reg |= ZR36057_VFESPFR_LittleEndian; /* RJ: I don't know, why the following has to be the opposite * of the corresponding ZR36060 setting, but only this way @@ -441,6 +441,7 @@ zr36057_set_vfe (struct zoran *zr, reg |= ZR36057_VFESPFR_TopField; switch (format->palette) { + case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_YUV422: reg |= ZR36057_VFESPFR_YUV422; break; diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 6e068cf1049..b3f28a03b6a 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5,7 +5,7 @@ * For use with LSI Logic PCI chip/adapter(s) * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ @@ -73,6 +73,7 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /* * cmd line parameters diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index a4afad4ecab..e316708f76b 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ @@ -72,11 +72,11 @@ #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.02" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.02" +#define MPT_LINUX_VERSION_COMMON "3.04.03" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.03" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -1059,7 +1059,7 @@ extern int mpt_stm_index; /* needed by mptstm.c */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* } __KERNEL__ */ -#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) +#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc__) #define CAST_U32_TO_PTR(x) ((void *)(u64)x) #define CAST_PTR_TO_U32(x) ((u32)(u64)x) #else diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 30975ccd994..504632da434 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -4,7 +4,7 @@ * For use with LSI Logic PCI chip/adapters * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ @@ -66,7 +66,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> -#define COPYRIGHT "Copyright (c) 1999-2005 LSI Logic Corporation" +#define COPYRIGHT "Copyright (c) 1999-2007 LSI Logic Corporation" #define MODULEAUTHOR "LSI Logic Corporation" #include "mptbase.h" #include "mptctl.h" @@ -79,6 +79,7 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h index 043941882c6..e65a1cf5eb0 100644 --- a/drivers/message/fusion/mptctl.h +++ b/drivers/message/fusion/mptctl.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index ca2f9107f14..c819c23b55b 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -3,7 +3,7 @@ * For use with LSI Logic PCI chip/adapter(s) * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ @@ -75,6 +75,7 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /* Command line args */ #define MPTFC_DEV_LOSS_TMO (60) diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index b7c4407c5e3..2936204d8ad 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -4,7 +4,7 @@ * For use with LSI Logic Fibre Channel PCI chip/adapters * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 2000-2005 LSI Logic Corporation + * Copyright (c) 2000-2007 LSI Logic Corporation * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -56,9 +56,11 @@ #include <linux/module.h> #include <linux/fs.h> +#define my_VERSION MPT_LINUX_VERSION_COMMON #define MYNAM "mptlan" MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 3726ecba570..70ab75e7c26 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -4,7 +4,7 @@ * For use with LSI Logic Fibre Channel PCI chip/adapters * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 2000-2005 LSI Logic Corporation + * Copyright (c) 2000-2007 LSI Logic Corporation * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 4f0c530e47b..09e9a9d9641 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -3,9 +3,9 @@ * For use with LSI Logic PCI chip/adapter(s) * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) - * Copyright (c) 2005-2006 Dell + * Copyright (c) 2005-2007 Dell */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -75,6 +75,7 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); static int mpt_pt_clear; module_param(mpt_pt_clear, int, 0); @@ -245,7 +246,8 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)); printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); - printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); + printk("SAS Address=0x%llX\n", (unsigned long long) + le64_to_cpu(sas_address)); printk("Target ID=0x%X\n", pg0->TargetID); printk("Bus=0x%X\n", pg0->Bus); /* The PhyNum field specifies the PHY number of the parent @@ -349,9 +351,9 @@ mptsas_port_delete(struct mptsas_portinfo_details * port_details) phy_info = port_info->phy_info; dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d " - "bitmask=0x%016llX\n", - __FUNCTION__, port_details, port_details->num_phys, - port_details->phy_bitmask)); + "bitmask=0x%016llX\n", __FUNCTION__, port_details, + port_details->num_phys, (unsigned long long) + port_details->phy_bitmask)); for (i = 0; i < port_info->num_phys; i++, phy_info++) { if(phy_info->port_details != port_details) @@ -476,7 +478,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { sas_address = phy_info->attached.sas_address; dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n", - i, sas_address)); + i, (unsigned long long)sas_address)); if (!sas_address) continue; port_details = phy_info->port_details; @@ -495,8 +497,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) (1 << phy_info->phy_id); phy_info->sas_port_add_phy=1; dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t" - "phy_id=%d sas_address=0x%018llX\n", - i, sas_address)); + "phy_id=%d sas_address=0x%018llX\n", + i, (unsigned long long)sas_address)); phy_info->port_details = port_details; } @@ -512,8 +514,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) if (phy_info_cmp->port_details == port_details ) continue; dsaswideprintk((KERN_DEBUG - "\t\tphy_id=%d sas_address=0x%018llX\n", - j, phy_info_cmp->attached.sas_address)); + "\t\tphy_id=%d sas_address=0x%018llX\n", + j, (unsigned long long) + phy_info_cmp->attached.sas_address)); if (phy_info_cmp->port_details) { port_details->rphy = mptsas_get_rphy(phy_info_cmp); @@ -546,11 +549,10 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) if (!port_details) continue; dsaswideprintk((KERN_DEBUG - "%s: [%p]: phy_id=%02d num_phys=%02d " - "bitmask=0x%016llX\n", - __FUNCTION__, - port_details, i, port_details->num_phys, - port_details->phy_bitmask)); + "%s: [%p]: phy_id=%02d num_phys=%02d " + "bitmask=0x%016llX\n", __FUNCTION__, + port_details, i, port_details->num_phys, + (unsigned long long)port_details->phy_bitmask)); dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n", port_details->port, port_details->rphy)); } @@ -2079,8 +2081,10 @@ mptsas_persist_clear_table(struct work_struct *work) static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { + int rc; + sdev->no_uld_attach = data ? 1 : 0; - scsi_device_reprobe(sdev); + rc = scsi_device_reprobe(sdev); } static void diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 2c72c36b817..f0cca3ea93b 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -3,7 +3,7 @@ * For use with LSI Logic PCI chip/adapter(s) * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ @@ -76,6 +76,7 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -701,6 +702,17 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) break; } } + } else if (ioc->bus_type == FC) { + /* + * The FC IOC may kill a request for variety of + * reasons, some of which may be recovered by a + * retry, some which are unlikely to be + * recovered. Return DID_ERROR instead of + * DID_RESET to permit retry of the command, + * just not an infinite number of them + */ + sc->result = DID_ERROR << 16; + break; } /* @@ -2688,7 +2700,8 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev) { dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", - hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd)); + hd->ioc->name, vtarget->bus_id, vtarget->target_id, + sdev->lun, hd)); /* Is LUN supported? If so, upper 2 bits will be 0 * in first byte of inquiry data. @@ -2770,7 +2783,7 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, else { factor = MPT_ULTRA320; if (scsi_device_qas(sdev)) { - ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id)); + ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id)); noQas = 0; } if (sdev->type == TYPE_TAPE && diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 14a5b6c2e2b..187c8af0890 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 36641da5928..203c661d2c7 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -3,7 +3,7 @@ * For use with LSI Logic PCI chip/adapter(s) * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2005 LSI Logic Corporation + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * */ @@ -77,6 +77,7 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /* Command line args */ static int mpt_saf_te = MPTSCSIH_SAF_TE; diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index a539d3b61e7..5278aad92bc 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -367,7 +367,7 @@ static int i2o_exec_remove(struct device *dev) /** * i2o_exec_lct_modified - Called on LCT NOTIFY reply - * @work: work struct for a specific controller + * @_work: work struct for a specific controller * * This function handles asynchronus LCT NOTIFY replies. It parses the * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index fdb7153f442..8e5e07e4c1c 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -317,7 +317,8 @@ static int __init msi_init(void) /* Register backlight stuff */ - msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props); + msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL, + &msibl_props); if (IS_ERR(msibl_device)) return PTR_ERR(msibl_device); diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 08a33c33f6e..aa152f31851 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -768,7 +768,7 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host) return IRQ_HANDLED; } -int at91_mci_get_ro(struct mmc_host *mmc) +static int at91_mci_get_ro(struct mmc_host *mmc) { int read_only = 0; struct at91mci_host *host = mmc_priv(mmc); @@ -794,7 +794,7 @@ static const struct mmc_host_ops at91_mci_ops = { /* * Probe for the device */ -static int at91_mci_probe(struct platform_device *pdev) +static int __init at91_mci_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct at91mci_host *host; @@ -910,7 +910,7 @@ static int at91_mci_probe(struct platform_device *pdev) /* * Remove a device */ -static int at91_mci_remove(struct platform_device *pdev) +static int __exit at91_mci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct at91mci_host *host; @@ -972,8 +972,7 @@ static int at91_mci_resume(struct platform_device *pdev) #endif static struct platform_driver at91_mci_driver = { - .probe = at91_mci_probe, - .remove = at91_mci_remove, + .remove = __exit_p(at91_mci_remove), .suspend = at91_mci_suspend, .resume = at91_mci_resume, .driver = { @@ -984,7 +983,7 @@ static struct platform_driver at91_mci_driver = { static int __init at91_mci_init(void) { - return platform_driver_register(&at91_mci_driver); + return platform_driver_probe(&at91_mci_driver, at91_mci_probe); } static void __exit at91_mci_exit(void) diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 06e7fcd1922..bfb9ff69320 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -351,9 +351,6 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, case MMC_RSP_R3: /* short */ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; break; - case MMC_RSP_R6: /* short CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R6; - break; default: break; } diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index e9b80e92026..ccfe6561be2 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -42,6 +42,8 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { writel(0, host->base + MMCICOMMAND); + BUG_ON(host->data); + host->mrq = NULL; host->cmd = NULL; @@ -198,6 +200,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, } if (!cmd->data || cmd->error != MMC_ERR_NONE) { + if (host->data) + mmci_stop_data(host); mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index 435d331e772..d30540b2761 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -91,7 +91,6 @@ #define DRIVER_NAME "mmci-omap" -#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) /* Specifies how often in millisecs to poll for card status changes * when the cover switch is open */ @@ -204,18 +203,22 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) cmdtype = 0; /* Our hardware needs to know exact type */ - switch (RSP_TYPE(mmc_resp_type(cmd))) { - case RSP_TYPE(MMC_RSP_R1): - /* resp 1, resp 1b */ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + break; + case MMC_RSP_R1: + case MMC_RSP_R1B: + /* resp 1, 1b, 6, 7 */ resptype = 1; break; - case RSP_TYPE(MMC_RSP_R2): + case MMC_RSP_R2: resptype = 2; break; - case RSP_TYPE(MMC_RSP_R3): + case MMC_RSP_R3: resptype = 3; break; default: + dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd)); break; } @@ -581,9 +584,9 @@ static void mmc_omap_switch_timer(unsigned long arg) schedule_work(&host->switch_work); } -static void mmc_omap_switch_handler(void *data) +static void mmc_omap_switch_handler(struct work_struct *work) { - struct mmc_omap_host *host = (struct mmc_omap_host *) data; + struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work); struct mmc_card *card; static int complained = 0; int cards = 0, cover_open; @@ -1116,7 +1119,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); if (host->switch_pin >= 0) { - INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host); + INIT_WORK(&host->switch_work, mmc_omap_switch_handler); init_timer(&host->switch_timer); host->switch_timer.function = mmc_omap_switch_timer; host->switch_timer.data = (unsigned long) host; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 45a9283ce49..6073d998b11 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -171,7 +171,7 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) switch (RSP_TYPE(mmc_resp_type(cmd))) { - case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */ + case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ cmdat |= CMDAT_RESP_SHORT; break; case RSP_TYPE(MMC_RSP_R3): diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index f18ad998b3c..fa4a52886b9 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -173,9 +173,6 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) case MMC_RSP_R3: rc |= TIFM_MMCSD_RSP_R3; break; - case MMC_RSP_R6: - rc |= TIFM_MMCSD_RSP_R6; - break; default: BUG(); } diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index a304b34c263..26f75c29944 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -164,9 +164,15 @@ config MTD_CHAR memory chips, and also use ioctl() to obtain information about the device, or to erase parts of it. +config MTD_BLKDEVS + tristate "Common interface to block layer for MTD 'translation layers'" + depends on MTD && BLOCK + default n + config MTD_BLOCK tristate "Caching block device access to MTD devices" depends on MTD && BLOCK + select MTD_BLKDEVS ---help--- Although most flash chips have an erase size too large to be useful as block devices, it is possible to use MTD devices which are based @@ -189,6 +195,7 @@ config MTD_BLOCK config MTD_BLOCK_RO tristate "Readonly block device access to MTD devices" depends on MTD_BLOCK!=y && MTD && BLOCK + select MTD_BLKDEVS help This allows you to mount read-only file systems (such as cramfs) from an MTD device, without the overhead (and danger) of the caching @@ -200,6 +207,7 @@ config MTD_BLOCK_RO config FTL tristate "FTL (Flash Translation Layer) support" depends on MTD && BLOCK + select MTD_BLKDEVS ---help--- This provides support for the original Flash Translation Layer which is part of the PCMCIA specification. It uses a kind of pseudo- @@ -216,6 +224,7 @@ config FTL config NFTL tristate "NFTL (NAND Flash Translation Layer) support" depends on MTD && BLOCK + select MTD_BLKDEVS ---help--- This provides support for the NAND Flash Translation Layer which is used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- @@ -239,6 +248,7 @@ config NFTL_RW config INFTL tristate "INFTL (Inverse NAND Flash Translation Layer) support" depends on MTD && BLOCK + select MTD_BLKDEVS ---help--- This provides support for the Inverse NAND Flash Translation Layer which is used on M-Systems' newer DiskOnChip devices. It @@ -256,6 +266,7 @@ config INFTL config RFD_FTL tristate "Resident Flash Disk (Flash Translation Layer) support" depends on MTD && BLOCK + select MTD_BLKDEVS ---help--- This provides support for the flash translation layer known as the Resident Flash Disk (RFD), as used by the Embedded BIOS @@ -265,8 +276,8 @@ config RFD_FTL config SSFDC tristate "NAND SSFDC (SmartMedia) read only translation layer" - depends on MTD - default n + depends on MTD && BLOCK + select MTD_BLKDEVS help This enables read only access to SmartMedia formatted NAND flash. You can mount it with FAT file system. diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 1e36b9aed98..c130e6261ad 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -15,13 +15,14 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_CHAR) += mtdchar.o -obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o -obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o -obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o -obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o -obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o -obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o -obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o +obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o +obj-$(CONFIG_MTD_BLOCK) += mtdblock.o +obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o +obj-$(CONFIG_FTL) += ftl.o +obj-$(CONFIG_NFTL) += nftl.o +obj-$(CONFIG_INFTL) += inftl.o +obj-$(CONFIG_RFD_FTL) += rfd_ftl.o +obj-$(CONFIG_SSFDC) += ssfdc.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 6a45be04564..52d51eb91c1 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -207,11 +207,10 @@ static int parse_afs_partitions(struct mtd_info *mtd, if (!sz) return ret; - parts = kmalloc(sz, GFP_KERNEL); + parts = kzalloc(sz, GFP_KERNEL); if (!parts) return -ENOMEM; - memset(parts, 0, sz); str = (char *)(parts + idx); /* diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index 16eaca69fb5..e7999f15d85 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c @@ -643,13 +643,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) int reg_idx; int offset; - mtd = (struct mtd_info*)kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) { printk(KERN_WARNING "%s: kmalloc failed for info structure\n", map->name); return NULL; } - memset(mtd, 0, sizeof(*mtd)); mtd->priv = map; memset(&temp, 0, sizeof(temp)); diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 296159ec518..f69184a92eb 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -337,12 +337,11 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) struct mtd_info *mtd; int i; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) { printk(KERN_ERR "Failed to allocate memory for MTD device\n"); return NULL; } - memset(mtd, 0, sizeof(*mtd)); mtd->priv = map; mtd->type = MTD_NORFLASH; @@ -2224,6 +2223,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) case FL_CFI_QUERY: case FL_JEDEC_QUERY: if (chip->oldstate == FL_READY) { + /* place the chip in a known state before suspend */ + map_write(map, CMD(0xFF), cfi->chips[i].start); chip->oldstate = chip->state; chip->state = FL_PM_SUSPENDED; /* No need to wake_up() on this state change - diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 702ae4cd869..e3acd398fb3 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -48,6 +48,7 @@ #define MANUFACTURER_ATMEL 0x001F #define MANUFACTURER_SST 0x00BF #define SST49LF004B 0x0060 +#define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 @@ -233,6 +234,7 @@ static struct cfi_fixup cfi_fixup_table[] = { }; static struct cfi_fixup jedec_fixup_table[] = { { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, + { MANUFACTURER_SST, SST49LF040B, fixup_use_fwh_lock, NULL, }, { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, { 0, 0, NULL, NULL } }; @@ -255,12 +257,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) struct mtd_info *mtd; int i; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) { printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); return NULL; } - memset(mtd, 0, sizeof(*mtd)); mtd->priv = map; mtd->type = MTD_NORFLASH; @@ -519,10 +520,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */ goto sleep; - if (!(mode == FL_READY || mode == FL_POINT + if (!( mode == FL_READY + || mode == FL_POINT || !cfip || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)) - || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)))) + || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1) + ))) goto sleep; /* We could check to see if we're trying to access the sector diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index fae70a5db54..d56849f5f10 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -172,7 +172,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) int i,j; unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips); if (!mtd) { @@ -181,7 +181,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) return NULL; } - memset(mtd, 0, sizeof(*mtd)); mtd->priv = map; mtd->type = MTD_NORFLASH; mtd->size = devsize * cfi->numchips; diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index cdb0f590b40..2eb696d7b97 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -40,7 +40,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) if (mtd) { if (mtd->size > map->size) { printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n", - (unsigned long)mtd->size >> 10, + (unsigned long)mtd->size >> 10, (unsigned long)map->size >> 10); mtd->size = map->size; } @@ -113,13 +113,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi } mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG; - chip_map = kmalloc(mapsize, GFP_KERNEL); + chip_map = kzalloc(mapsize, GFP_KERNEL); if (!chip_map) { printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); kfree(cfi.cfiq); return NULL; } - memset (chip_map, 0, mapsize); set_bit(0, chip_map); /* Mark first chip valid */ diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index 2c3f019197c..14e57b2bf84 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c @@ -116,11 +116,10 @@ static struct mtd_info *jedec_probe(struct map_info *map) char Part[200]; memset(&priv,0,sizeof(priv)); - MTD = kmalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL); + MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL); if (!MTD) return NULL; - memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); priv = (struct jedec_private *)&MTD[1]; my_bank_size = map->size; diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 1154dac715a..58e561e8769 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -154,6 +154,7 @@ #define SST39SF010A 0x00B5 #define SST39SF020A 0x00B6 #define SST49LF004B 0x0060 +#define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define SST49LF030A 0x001C #define SST49LF040A 0x0051 @@ -1401,6 +1402,20 @@ static const struct amd_flash_info jedec_table[] = { } }, { .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF040B, + .name = "SST 49LF040B", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,128), + } + }, { + + .mfr_id = MANUFACTURER_SST, .dev_id = SST49LF004B, .name = "SST 49LF004B", .uaddr = { @@ -1874,7 +1889,7 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) /* - * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing + * There is a BIG problem properly ID'ing the JEDEC device and guaranteeing * the mapped address, unlock addresses, and proper chip ID. This function * attempts to minimize errors. It is doubtfull that this probe will ever * be perfect - consequently there should be some module parameters that diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index ac01a949b68..fc478c0f93f 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c @@ -47,13 +47,11 @@ static struct mtd_info *map_absent_probe(struct map_info *map) { struct mtd_info *mtd; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) { return NULL; } - memset(mtd, 0, sizeof(*mtd)); - map->fldrv = &map_absent_chipdrv; mtd->priv = map; mtd->name = map->name; diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 3a66680abfd..5cb6d526366 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c @@ -55,12 +55,10 @@ static struct mtd_info *map_ram_probe(struct map_info *map) #endif /* OK. It seems to be RAM. */ - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) return NULL; - memset(mtd, 0, sizeof(*mtd)); - map->fldrv = &mapram_chipdrv; mtd->priv = map; mtd->name = map->name; diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index 1b328b1378f..cb27f855074 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -31,12 +31,10 @@ static struct mtd_info *map_rom_probe(struct map_info *map) { struct mtd_info *mtd; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) return NULL; - memset(mtd, 0, sizeof(*mtd)); - map->fldrv = &maprom_chipdrv; mtd->priv = map; mtd->name = map->name; diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c index 967abbecdff..c9cd3d21ccf 100644 --- a/drivers/mtd/chips/sharp.c +++ b/drivers/mtd/chips/sharp.c @@ -112,18 +112,16 @@ static struct mtd_info *sharp_probe(struct map_info *map) struct sharp_info *sharp = NULL; int width; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if(!mtd) return NULL; - sharp = kmalloc(sizeof(*sharp), GFP_KERNEL); + sharp = kzalloc(sizeof(*sharp), GFP_KERNEL); if(!sharp) { kfree(mtd); return NULL; } - memset(mtd, 0, sizeof(*mtd)); - width = sharp_probe_map(map,mtd); if(!width){ kfree(mtd); @@ -143,7 +141,6 @@ static struct mtd_info *sharp_probe(struct map_info *map) mtd->writesize = 1; mtd->name = map->name; - memset(sharp, 0, sizeof(*sharp)); sharp->chipshift = 23; sharp->numchips = 1; sharp->chips[0].start = 0; diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index a7a7bfe3387..23fab14f163 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -163,13 +163,12 @@ static struct mtd_partition * newpart(char *s, *num_parts = this_part + 1; alloc_size = *num_parts * sizeof(struct mtd_partition) + extra_mem_size; - parts = kmalloc(alloc_size, GFP_KERNEL); + parts = kzalloc(alloc_size, GFP_KERNEL); if (!parts) { printk(KERN_ERR ERRP "out of memory\n"); return NULL; } - memset(parts, 0, alloc_size); extra_mem = (unsigned char *)(parts + *num_parts); } /* enter this partition (offset will be calculated later if it is zero at this point) */ @@ -346,7 +345,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, * * This function needs to be visible for bootloaders. */ -int mtdpart_setup(char *s) +static int mtdpart_setup(char *s) { cmdline = s; return 1; diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 401c6a294ba..6d917a4daa9 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -295,10 +295,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) if (!devname) return NULL; - dev = kmalloc(sizeof(struct block2mtd_dev), GFP_KERNEL); + dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL); if (!dev) return NULL; - memset(dev, 0, sizeof(*dev)); /* Get a handle on the device */ bdev = open_bdev_excl(devname, O_RDWR, NULL); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 334e078ffaf..78c2511ae9e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -437,7 +437,7 @@ static int __devinit m25p_probe(struct spi_device *spi) * or JEDEC get-id commands. Try them ... */ DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n", - flash->spi->dev.bus_id); + spi->dev.bus_id); return -ENODEV; } @@ -447,7 +447,7 @@ static int __devinit m25p_probe(struct spi_device *spi) } if (i == ARRAY_SIZE(m25p_data)) { DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n", - flash->spi->dev.bus_id, data->type); + spi->dev.bus_id, data->type); return -ENODEV; } diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 08dfb899b27..9cff119a202 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -131,11 +131,10 @@ static int __init ms02nv_init_one(ulong addr) int ret = -ENODEV; /* The module decodes 8MiB of address space. */ - mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL); + mod_res = kzalloc(sizeof(*mod_res), GFP_KERNEL); if (!mod_res) return -ENOMEM; - memset(mod_res, 0, sizeof(*mod_res)); mod_res->name = ms02nv_name; mod_res->start = addr; mod_res->end = addr + MS02NV_SLOT_SIZE - 1; @@ -153,24 +152,21 @@ static int __init ms02nv_init_one(ulong addr) } ret = -ENOMEM; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) goto err_out_mod_res_rel; - memset(mtd, 0, sizeof(*mtd)); - mp = kmalloc(sizeof(*mp), GFP_KERNEL); + mp = kzalloc(sizeof(*mp), GFP_KERNEL); if (!mp) goto err_out_mtd; - memset(mp, 0, sizeof(*mp)); mtd->priv = mp; mp->resource.module = mod_res; /* Firmware's diagnostic NVRAM area. */ - diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL); + diag_res = kzalloc(sizeof(*diag_res), GFP_KERNEL); if (!diag_res) goto err_out_mp; - memset(diag_res, 0, sizeof(*diag_res)); diag_res->name = ms02nv_res_diag_ram; diag_res->start = addr; diag_res->end = addr + MS02NV_RAM - 1; @@ -180,11 +176,10 @@ static int __init ms02nv_init_one(ulong addr) mp->resource.diag_ram = diag_res; /* User-available general-purpose NVRAM area. */ - user_res = kmalloc(sizeof(*user_res), GFP_KERNEL); + user_res = kzalloc(sizeof(*user_res), GFP_KERNEL); if (!user_res) goto err_out_diag_res; - memset(user_res, 0, sizeof(*user_res)); user_res->name = ms02nv_res_user_ram; user_res->start = addr + MS02NV_RAM; user_res->end = addr + size - 1; @@ -194,11 +189,10 @@ static int __init ms02nv_init_one(ulong addr) mp->resource.user_ram = user_res; /* Control and status register. */ - csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL); + csr_res = kzalloc(sizeof(*csr_res), GFP_KERNEL); if (!csr_res) goto err_out_user_res; - memset(csr_res, 0, sizeof(*csr_res)); csr_res->name = ms02nv_res_csr; csr_res->start = addr + MS02NV_CSR; csr_res->end = addr + MS02NV_CSR + 3; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 0a7e86859bf..a987e917f4e 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -480,7 +480,7 @@ add_dataflash(struct spi_device *spi, char *name, device->writesize = pagesize; device->owner = THIS_MODULE; device->type = MTD_DATAFLASH; - device->flags = MTD_CAP_NORFLASH; + device->flags = MTD_WRITEABLE; device->erase = dataflash_erase; device->read = dataflash_read; device->write = dataflash_write; @@ -536,7 +536,7 @@ static int __devinit dataflash_probe(struct spi_device *spi) if (status <= 0 || status == 0xff) { DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", spi->dev.bus_id, status); - if (status == 0xff) + if (status == 0 || status == 0xff) status = -ENODEV; return status; } diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 6c7337f9ebb..56cc1ca7ffd 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -126,12 +126,10 @@ static int register_device(char *name, unsigned long start, unsigned long len) struct phram_mtd_list *new; int ret = -ENOMEM; - new = kmalloc(sizeof(*new), GFP_KERNEL); + new = kzalloc(sizeof(*new), GFP_KERNEL); if (!new) goto out0; - memset(new, 0, sizeof(*new)); - ret = -EIO; new->mtd.priv = ioremap(start, len); if (!new->mtd.priv) { diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 542a0c00900..5f49248a485 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -168,19 +168,16 @@ static int register_device(char *name, unsigned long start, unsigned long length E("slram: Cannot allocate new MTD device.\n"); return(-ENOMEM); } - (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); + (*curmtd)->mtdinfo = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); (*curmtd)->next = NULL; if ((*curmtd)->mtdinfo) { - memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info)); (*curmtd)->mtdinfo->priv = - kmalloc(sizeof(slram_priv_t), GFP_KERNEL); + kzalloc(sizeof(slram_priv_t), GFP_KERNEL); if (!(*curmtd)->mtdinfo->priv) { kfree((*curmtd)->mtdinfo); (*curmtd)->mtdinfo = NULL; - } else { - memset((*curmtd)->mtdinfo->priv,0,sizeof(slram_priv_t)); } } diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 8a878b34eca..24235d4f1d2 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1033,7 +1033,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { partition_t *partition; - partition = kmalloc(sizeof(partition_t), GFP_KERNEL); + partition = kzalloc(sizeof(partition_t), GFP_KERNEL); if (!partition) { printk(KERN_WARNING "No memory to scan for FTL on %s\n", @@ -1041,8 +1041,6 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - memset(partition, 0, sizeof(partition_t)); - partition->mbd.mtd = mtd; if ((scan_header(partition) == 0) && @@ -1054,7 +1052,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) le32_to_cpu(partition->header.FormattedSize) >> 10); #endif partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9; - partition->mbd.blksize = SECTOR_SIZE; + partition->mbd.tr = tr; partition->mbd.devnum = -1; if (!add_mtd_blktrans_dev((void *)partition)) @@ -1076,6 +1074,7 @@ struct mtd_blktrans_ops ftl_tr = { .name = "ftl", .major = FTL_MAJOR, .part_bits = PART_BITS, + .blksize = SECTOR_SIZE, .readsect = ftl_readsect, .writesect = ftl_writesect, .getgeo = ftl_getgeo, diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 4116535805f..b0e396504e6 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -67,17 +67,16 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); - inftl = kmalloc(sizeof(*inftl), GFP_KERNEL); + inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); if (!inftl) { printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); return; } - memset(inftl, 0, sizeof(*inftl)); inftl->mbd.mtd = mtd; inftl->mbd.devnum = -1; - inftl->mbd.blksize = 512; + inftl->mbd.tr = tr; if (INFTL_mount(inftl) < 0) { @@ -163,10 +162,9 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, ops.ooblen = len; ops.oobbuf = buf; ops.datbuf = NULL; - ops.len = len; res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops); - *retlen = ops.retlen; + *retlen = ops.oobretlen; return res; } @@ -184,10 +182,9 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, ops.ooblen = len; ops.oobbuf = buf; ops.datbuf = NULL; - ops.len = len; res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops); - *retlen = ops.retlen; + *retlen = ops.oobretlen; return res; } @@ -945,6 +942,7 @@ static struct mtd_blktrans_ops inftl_tr = { .name = "inftl", .major = INFTL_MAJOR, .part_bits = INFTL_PARTN_BITS, + .blksize = 512, .getgeo = inftl_getgeo, .readsect = inftl_readblock, .writesect = inftl_writeblock, diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index d132ed571f1..f457315579d 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -60,6 +60,15 @@ config MTD_PHYSMAP_BANKWIDTH Ignore this option if you use run-time physmap configuration (i.e., run-time calling physmap_configure()). +config MTD_PHYSMAP_OF + tristate "Flash device in physical memory map based on OF descirption" + depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM) + help + This provides a 'mapping' driver which allows the NOR Flash and + ROM driver code to communicate with chips which are mapped + physically into the CPU's memory. The mapping description here is + taken from OF device tree. + config MTD_SUN_UFLASH tristate "Sun Microsystems userflash support" depends on SPARC && MTD_CFI @@ -184,6 +193,24 @@ config MTD_ICHXROM BE VERY CAREFUL. +config MTD_ESB2ROM + tristate "BIOS flash chip on Intel ESB Controller Hub 2" + depends on X86 && MTD_JEDECPROBE && PCI + help + Support for treating the BIOS flash chip on ESB2 motherboards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + +config MTD_CK804XROM + tristate "BIOS flash chip on Nvidia CK804" + depends on X86 && MTD_JEDECPROBE + help + Support for treating the BIOS flash chip on nvidia motherboards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + config MTD_SCB2_FLASH tristate "BIOS flash chip on Intel SCB2 boards" depends on X86 && MTD_JEDECPROBE @@ -355,50 +382,6 @@ config MTD_TQM834x TQ Components TQM834x boards. If you have one of these boards and would like to use the flash chips on it, say 'Y'. -config MTD_CSTM_MIPS_IXX - tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" - depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS - help - This provides a mapping driver for the Integrated Technology - Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR - Reference Board. It provides the necessary addressing, length, - buswidth, vpp code and addition setup of the flash device for - these boards. In addition, this mapping driver can be used for - other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/ - LEN/BUSWIDTH parameters. This mapping will provide one mtd device - using one partition. The start address can be offset from the - beginning of flash and the len can be less than the total flash - device size to allow a window into the flash. Both CFI and JEDEC - probes are called. - -config MTD_CSTM_MIPS_IXX_START - hex "Physical start address of flash mapping" - depends on MTD_CSTM_MIPS_IXX - default "0x8000000" - help - This is the physical memory location that the MTD driver will - use for the flash chips on your particular target board. - Refer to the memory map which should hopefully be in the - documentation for your board. - -config MTD_CSTM_MIPS_IXX_LEN - hex "Physical length of flash mapping" - depends on MTD_CSTM_MIPS_IXX - default "0x4000000" - help - This is the total length that the MTD driver will use for the - flash chips on your particular board. Refer to the memory - map which should hopefully be in the documentation for your - board. - -config MTD_CSTM_MIPS_IXX_BUSWIDTH - int "Bus width in octets" - depends on MTD_CSTM_MIPS_IXX - default "2" - help - This is the total bus width of the mapping of the flash chips - on your particular board. - config MTD_OCELOT tristate "Momenco Ocelot boot flash device" depends on MIPS && MOMENCO_OCELOT diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 191c1928bbe..071d0bf922b 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -12,12 +12,13 @@ obj-$(CONFIG_MTD_CDB89712) += cdb89712.o obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o obj-$(CONFIG_MTD_BAST) += bast-flash.o obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o -obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_L440GX) += l440gx.o obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o +obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o +obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o @@ -25,6 +26,7 @@ obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o +obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o obj-$(CONFIG_MTD_PNC2000) += pnc2000.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 797caffb20b..78b671172bb 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/types.h> +#include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/io.h> @@ -44,6 +45,23 @@ struct amd76xrom_map_info { char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; }; +/* The 2 bits controlling the window size are often set to allow reading + * the BIOS, but too small to allow writing, since the lock registers are + * 4MiB lower in the address space than the data. + * + * This is intended to prevent flashing the bios, perhaps accidentally. + * + * This parameter allows the normal driver to over-ride the BIOS settings. + * + * The bits are 6 and 7. If both bits are set, it is a 5MiB window. + * If only the 7 Bit is set, it is a 4MiB window. Otherwise, a + * 64KiB window. + * + */ +static uint win_size_bits; +module_param(win_size_bits, uint, 0); +MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS."); + static struct amd76xrom_window amd76xrom_window = { .maps = LIST_HEAD_INIT(amd76xrom_window.maps), }; @@ -95,6 +113,16 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, /* Remember the pci dev I find the window in - already have a ref */ window->pdev = pdev; + /* Enable the selected rom window. This is often incorrectly + * set up by the BIOS, and the 4MiB offset for the lock registers + * requires the full 5MiB of window space. + * + * This 'write, then read' approach leaves the bits for + * other uses of the hardware info. + */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | win_size_bits ); + /* Assume the rom window is properly setup, and find it's size */ pci_read_config_byte(pdev, 0x43, &byte); if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) { @@ -129,12 +157,6 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, (unsigned long long)window->rsrc.end); } -#if 0 - - /* Enable the selected rom window */ - pci_read_config_byte(pdev, 0x43, &byte); - pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits); -#endif /* Enable writes through the rom window */ pci_read_config_byte(pdev, 0x40, &byte); diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index e074bb6787d..fc3b2672d1e 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c @@ -131,7 +131,7 @@ static int bast_flash_probe(struct platform_device *pdev) info->map.phys = res->start; info->map.size = res->end - res->start + 1; - info->map.name = pdev->dev.bus_id; + info->map.name = pdev->dev.bus_id; info->map.bankwidth = 2; if (info->map.size > AREA_MAXSIZE) diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index 0402c21e291..629e6e2641a 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -122,10 +122,9 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info /* * Allocate the map_info structs in one go. */ - maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); + maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL); if (!maps) return -ENOMEM; - memset(maps, 0, sizeof(struct map_info) * nr); /* * Claim and then map the memory regions. */ diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c new file mode 100644 index 00000000000..238d42e88ec --- /dev/null +++ b/drivers/mtd/maps/ck804xrom.c @@ -0,0 +1,356 @@ +/* + * ck804xrom.c + * + * Normal mappings of chips in physical memory + * + * Dave Olsen <dolsen@lnxi.com> + * Ryan Jackson <rjackson@lnxi.com> + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/flashchip.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/list.h> + + +#define MOD_NAME KBUILD_BASENAME + +#define ADDRESS_NAME_LEN 18 + +#define ROM_PROBE_STEP_SIZE (64*1024) + +struct ck804xrom_window { + void __iomem *virt; + unsigned long phys; + unsigned long size; + struct list_head maps; + struct resource rsrc; + struct pci_dev *pdev; +}; + +struct ck804xrom_map_info { + struct list_head list; + struct map_info map; + struct mtd_info *mtd; + struct resource rsrc; + char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; +}; + + +/* The 2 bits controlling the window size are often set to allow reading + * the BIOS, but too small to allow writing, since the lock registers are + * 4MiB lower in the address space than the data. + * + * This is intended to prevent flashing the bios, perhaps accidentally. + * + * This parameter allows the normal driver to override the BIOS settings. + * + * The bits are 6 and 7. If both bits are set, it is a 5MiB window. + * If only the 7 Bit is set, it is a 4MiB window. Otherwise, a + * 64KiB window. + * + */ +static uint win_size_bits = 0; +module_param(win_size_bits, uint, 0); +MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x88 byte, normally set by BIOS."); + +static struct ck804xrom_window ck804xrom_window = { + .maps = LIST_HEAD_INIT(ck804xrom_window.maps), +}; + +static void ck804xrom_cleanup(struct ck804xrom_window *window) +{ + struct ck804xrom_map_info *map, *scratch; + u8 byte; + + if (window->pdev) { + /* Disable writes through the rom window */ + pci_read_config_byte(window->pdev, 0x6d, &byte); + pci_write_config_byte(window->pdev, 0x6d, byte & ~1); + } + + /* Free all of the mtd devices */ + list_for_each_entry_safe(map, scratch, &window->maps, list) { + if (map->rsrc.parent) + release_resource(&map->rsrc); + + del_mtd_device(map->mtd); + map_destroy(map->mtd); + list_del(&map->list); + kfree(map); + } + if (window->rsrc.parent) + release_resource(&window->rsrc); + + if (window->virt) { + iounmap(window->virt); + window->virt = NULL; + window->phys = 0; + window->size = 0; + } + pci_dev_put(window->pdev); +} + + +static int __devinit ck804xrom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; + u8 byte; + struct ck804xrom_window *window = &ck804xrom_window; + struct ck804xrom_map_info *map = NULL; + unsigned long map_top; + + /* Remember the pci dev I find the window in */ + window->pdev = pci_dev_get(pdev); + + /* Enable the selected rom window. This is often incorrectly + * set up by the BIOS, and the 4MiB offset for the lock registers + * requires the full 5MiB of window space. + * + * This 'write, then read' approach leaves the bits for + * other uses of the hardware info. + */ + pci_read_config_byte(pdev, 0x88, &byte); + pci_write_config_byte(pdev, 0x88, byte | win_size_bits ); + + + /* Assume the rom window is properly setup, and find it's size */ + pci_read_config_byte(pdev, 0x88, &byte); + + if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) + window->phys = 0xffb00000; /* 5MiB */ + else if ((byte & (1<<7)) == (1<<7)) + window->phys = 0xffc00000; /* 4MiB */ + else + window->phys = 0xffff0000; /* 64KiB */ + + window->size = 0xffffffffUL - window->phys + 1UL; + + /* + * Try to reserve the window mem region. If this fails then + * it is likely due to a fragment of the window being + * "reserved" by the BIOS. In the case that the + * request_mem_region() fails then once the rom size is + * discovered we will try to reserve the unreserved fragment. + */ + window->rsrc.name = MOD_NAME; + window->rsrc.start = window->phys; + window->rsrc.end = window->phys + window->size - 1; + window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &window->rsrc)) { + window->rsrc.parent = NULL; + printk(KERN_ERR MOD_NAME + " %s(): Unable to register resource" + " 0x%.016llx-0x%.016llx - kernel bug?\n", + __func__, + (unsigned long long)window->rsrc.start, + (unsigned long long)window->rsrc.end); + } + + + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, 0x6d, &byte); + pci_write_config_byte(pdev, 0x6d, byte | 1); + + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + + /* For write accesses caches are useless */ + window->virt = ioremap_nocache(window->phys, window->size); + if (!window->virt) { + printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n", + window->phys, window->size); + goto out; + } + + /* Get the first address to look for a rom chip at */ + map_top = window->phys; +#if 1 + /* The probe sequence run over the firmware hub lock + * registers sets them to 0x7 (no access). + * Probe at most the last 4MiB of the address space. + */ + if (map_top < 0xffc00000) + map_top = 0xffc00000; +#endif + /* Loop through and look for rom chips. Since we don't know the + * starting address for each chip, probe every ROM_PROBE_STEP_SIZE + * bytes from the starting address of the window. + */ + while((map_top - 1) < 0xffffffffUL) { + struct cfi_private *cfi; + unsigned long offset; + int i; + + if (!map) + map = kmalloc(sizeof(*map), GFP_KERNEL); + + if (!map) { + printk(KERN_ERR MOD_NAME ": kmalloc failed"); + goto out; + } + memset(map, 0, sizeof(*map)); + INIT_LIST_HEAD(&map->list); + map->map.name = map->map_name; + map->map.phys = map_top; + offset = map_top - window->phys; + map->map.virt = (void __iomem *) + (((unsigned long)(window->virt)) + offset); + map->map.size = 0xffffffffUL - map_top + 1UL; + /* Set the name of the map to the address I am trying */ + sprintf(map->map_name, "%s @%08lx", + MOD_NAME, map->map.phys); + + /* There is no generic VPP support */ + for(map->map.bankwidth = 32; map->map.bankwidth; + map->map.bankwidth >>= 1) + { + char **probe_type; + /* Skip bankwidths that are not supported */ + if (!map_bankwidth_supported(map->map.bankwidth)) + continue; + + /* Setup the map methods */ + simple_map_init(&map->map); + + /* Try all of the probe methods */ + probe_type = rom_probe_types; + for(; *probe_type; probe_type++) { + map->mtd = do_map_probe(*probe_type, &map->map); + if (map->mtd) + goto found; + } + } + map_top += ROM_PROBE_STEP_SIZE; + continue; + found: + /* Trim the size if we are larger than the map */ + if (map->mtd->size > map->map.size) { + printk(KERN_WARNING MOD_NAME + " rom(%u) larger than window(%lu). fixing...\n", + map->mtd->size, map->map.size); + map->mtd->size = map->map.size; + } + if (window->rsrc.parent) { + /* + * Registering the MTD device in iomem may not be possible + * if there is a BIOS "reserved" and BUSY range. If this + * fails then continue anyway. + */ + map->rsrc.name = map->map_name; + map->rsrc.start = map->map.phys; + map->rsrc.end = map->map.phys + map->mtd->size - 1; + map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&window->rsrc, &map->rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve MTD resource\n"); + map->rsrc.parent = NULL; + } + } + + /* Make the whole region visible in the map */ + map->map.virt = window->virt; + map->map.phys = window->phys; + cfi = map->map.fldrv_priv; + for(i = 0; i < cfi->numchips; i++) + cfi->chips[i].start += offset; + + /* Now that the mtd devices is complete claim and export it */ + map->mtd->owner = THIS_MODULE; + if (add_mtd_device(map->mtd)) { + map_destroy(map->mtd); + map->mtd = NULL; + goto out; + } + + + /* Calculate the new value of map_top */ + map_top += map->mtd->size; + + /* File away the map structure */ + list_add(&map->list, &window->maps); + map = NULL; + } + + out: + /* Free any left over map structures */ + if (map) + kfree(map); + + /* See if I have any map structures */ + if (list_empty(&window->maps)) { + ck804xrom_cleanup(window); + return -ENODEV; + } + return 0; +} + + +static void __devexit ck804xrom_remove_one (struct pci_dev *pdev) +{ + struct ck804xrom_window *window = &ck804xrom_window; + + ck804xrom_cleanup(window); +} + +static struct pci_device_id ck804xrom_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA, 0x0051, + PCI_ANY_ID, PCI_ANY_ID, }, /* nvidia ck804 */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, ck804xrom_pci_tbl); + +#if 0 +static struct pci_driver ck804xrom_driver = { + .name = MOD_NAME, + .id_table = ck804xrom_pci_tbl, + .probe = ck804xrom_init_one, + .remove = ck804xrom_remove_one, +}; +#endif + +static int __init init_ck804xrom(void) +{ + struct pci_dev *pdev; + struct pci_device_id *id; + int retVal; + pdev = NULL; + + for(id = ck804xrom_pci_tbl; id->vendor; id++) { + pdev = pci_find_device(id->vendor, id->device, NULL); + if (pdev) + break; + } + if (pdev) { + retVal = ck804xrom_init_one(pdev, &ck804xrom_pci_tbl[0]); + pci_dev_put(pdev); + return retVal; + } + return -ENXIO; +#if 0 + return pci_module_init(&ck804xrom_driver); +#endif +} + +static void __exit cleanup_ck804xrom(void) +{ + ck804xrom_remove_one(ck804xrom_window.pdev); +} + +module_init(init_ck804xrom); +module_exit(cleanup_ck804xrom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>, Dave Olsen <dolsen@lnxi.com>"); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the Nvidia ck804 southbridge"); + diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c deleted file mode 100644 index df2c38ef105..00000000000 --- a/drivers/mtd/maps/cstm_mips_ixx.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ - * - * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. - * Config with both CFI and JEDEC device support. - * - * Basically physmap.c with the addition of partitions and - * an array of mapping info to accomodate more than one flash type per board. - * - * Copyright 2000 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> -#include <linux/delay.h> - -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -#define CC_GCR 0xB4013818 -#define CC_GPBCR 0xB401380A -#define CC_GPBDR 0xB4013808 -#define CC_M68K_DEVICE 1 -#define CC_M68K_FUNCTION 6 -#define CC_CONFADDR 0xB8004000 -#define CC_CONFDATA 0xB8004004 -#define CC_FC_FCR 0xB8002004 -#define CC_FC_DCR 0xB8002008 -#define CC_GPACR 0xB4013802 -#define CC_GPAICR 0xB4013804 -#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ - -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) -{ - static DEFINE_SPINLOCK(vpp_lock); - static int vpp_count = 0; - unsigned long flags; - - spin_lock_irqsave(&vpp_lock, flags); - - if (vpp) { - if (!vpp_count++) { - __u16 data; - __u8 data1; - static u8 first = 1; - - // Set GPIO port B pin3 to high - data = *(__u16 *)(CC_GPBCR); - data = (data & 0xff0f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08; - if (first) { - first = 0; - /* need to have this delay for first - enabling vpp after powerup */ - udelay(40); - } - } - } else { - if (!--vpp_count) { - __u16 data; - - // Set GPIO port B pin3 to high - data = *(__u16 *)(CC_GPBCR); - data = (data & 0xff3f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7; - } - } - spin_unlock_irqrestore(&vpp_lock, flags); -} -#endif - -/* board and partition description */ - -#define MAX_PHYSMAP_PARTITIONS 8 -struct cstm_mips_ixx_info { - char *name; - unsigned long window_addr; - unsigned long window_size; - int bankwidth; - int num_partitions; -}; - -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type -const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = -{ - { // 28F128J3A in 2x16 configuration - "big flash", // name - 0x08000000, // window_addr - 0x02000000, // window_size - 4, // bankwidth - 1, // num_partitions - } - -}; -static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { -{ // 28F128J3A in 2x16 configuration - { - .name = "main partition ", - .size = 0x02000000, // 128 x 2 x 128k byte sectors - .offset = 0, - }, -}, -}; -#else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ -#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type -const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = -{ - { - "MTD flash", // name - CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr - CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size - CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // bankwidth - 1, // num_partitions - }, - -}; -static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { -{ - { - .name = "main partition", - .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, - .offset = 0, - }, -}, -}; -#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ - -struct map_info cstm_mips_ixx_map[PHYSMAP_NUMBER]; - -int __init init_cstm_mips_ixx(void) -{ - int i; - int jedec; - struct mtd_info *mymtd; - struct mtd_partition *parts; - - /* Initialize mapping */ - for (i=0;i<PHYSMAP_NUMBER;i++) { - printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", - cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); - - - cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr; - cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); - if (!cstm_mips_ixx_map[i].virt) { - int j = 0; - printk(KERN_WARNING "Failed to ioremap\n"); - for (j = 0; j < i; j++) { - if (cstm_mips_ixx_map[j].virt) { - iounmap(cstm_mips_ixx_map[j].virt); - cstm_mips_ixx_map[j].virt = NULL; - } - } - return -EIO; - } - cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name; - cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size; - cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth; -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp; -#endif - simple_map_init(&cstm_mips_ixx_map[i]); - //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt)); - } - -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - setup_ITE_IVR_flash(); -#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ - - for (i=0;i<PHYSMAP_NUMBER;i++) { - parts = &cstm_mips_ixx_partitions[i][0]; - jedec = 0; - mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &cstm_mips_ixx_map[i]); - //printk(KERN_NOTICE "phymap %d cfi_probe: mymtd is %x\n",i,(unsigned int)mymtd); - if (!mymtd) { - jedec = 1; - mymtd = (struct mtd_info *)do_map_probe("jedec", &cstm_mips_ixx_map[i]); - printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd); - } - if (mymtd) { - mymtd->owner = THIS_MODULE; - - cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd; - add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions); - } - else { - for (i = 0; i < PHYSMAP_NUMBER; i++) { - if (cstm_mips_ixx_map[i].virt) { - iounmap(cstm_mips_ixx_map[i].virt); - cstm_mips_ixx_map[i].virt = NULL; - } - } - return -ENXIO; - } - } - return 0; -} - -static void __exit cleanup_cstm_mips_ixx(void) -{ - int i; - struct mtd_info *mymtd; - - for (i=0;i<PHYSMAP_NUMBER;i++) { - mymtd = (struct mtd_info *)cstm_mips_ixx_map[i].map_priv_2; - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } - if (cstm_mips_ixx_map[i].virt) { - iounmap((void *)cstm_mips_ixx_map[i].virt); - cstm_mips_ixx_map[i].virt = 0; - } - } -} -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 data) -{ - __u32 offset; - - offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ; - - *(__u32 *)CC_CONFADDR = offset; - *(__u32 *)CC_CONFDATA = data; -} -void setup_ITE_IVR_flash() -{ - __u32 size, base; - - size = 0x0e000000; // 32MiB - base = (0x08000000) >> 8 >>1; // Bug: we must shift one more bit - - /* need to set ITE flash to 32 bits instead of default 8 */ -#ifdef CONFIG_MIPS_IVR - *(__u32 *)CC_FC_FCR = 0x55; - *(__u32 *)CC_GPACR = 0xfffc; -#else - *(__u32 *)CC_FC_FCR = 0x77; -#endif - /* turn bursting off */ - *(__u32 *)CC_FC_DCR = 0x0; - - /* setup for one chip 4 byte PCI access */ - PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x60, size | base); - PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x64, 0x02); -} -#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ - -module_init(init_cstm_mips_ixx); -module_exit(cleanup_cstm_mips_ixx); - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>"); -MODULE_DESCRIPTION("MTD map driver for ITE 8172G and Globespan IVR boards"); diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c new file mode 100644 index 00000000000..a9d808a617c --- /dev/null +++ b/drivers/mtd/maps/esb2rom.c @@ -0,0 +1,450 @@ +/* + * esb2rom.c + * + * Normal mappings of flash chips in physical memory + * through the Intel ESB2 Southbridge. + * + * This was derived from ichxrom.c in May 2006 by + * Lew Glendenning <lglendenning@lnxi.com> + * + * Eric Biederman, of course, was a major help in this effort. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/flashchip.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/list.h> + +#define MOD_NAME KBUILD_BASENAME + +#define ADDRESS_NAME_LEN 18 + +#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */ + +#define BIOS_CNTL 0xDC +#define BIOS_LOCK_ENABLE 0x02 +#define BIOS_WRITE_ENABLE 0x01 + +/* This became a 16-bit register, and EN2 has disappeared */ +#define FWH_DEC_EN1 0xD8 +#define FWH_F8_EN 0x8000 +#define FWH_F0_EN 0x4000 +#define FWH_E8_EN 0x2000 +#define FWH_E0_EN 0x1000 +#define FWH_D8_EN 0x0800 +#define FWH_D0_EN 0x0400 +#define FWH_C8_EN 0x0200 +#define FWH_C0_EN 0x0100 +#define FWH_LEGACY_F_EN 0x0080 +#define FWH_LEGACY_E_EN 0x0040 +/* reserved 0x0020 and 0x0010 */ +#define FWH_70_EN 0x0008 +#define FWH_60_EN 0x0004 +#define FWH_50_EN 0x0002 +#define FWH_40_EN 0x0001 + +/* these are 32-bit values */ +#define FWH_SEL1 0xD0 +#define FWH_SEL2 0xD4 + +#define FWH_8MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \ + FWH_70_EN | FWH_60_EN | FWH_50_EN | FWH_40_EN) + +#define FWH_7MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \ + FWH_70_EN | FWH_60_EN | FWH_50_EN) + +#define FWH_6MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \ + FWH_70_EN | FWH_60_EN) + +#define FWH_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \ + FWH_70_EN) + +#define FWH_4MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN) + +#define FWH_3_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN | FWH_C8_EN) + +#define FWH_3MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN | FWH_D0_EN) + +#define FWH_2_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \ + FWH_D8_EN) + +#define FWH_2MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN) + +#define FWH_1_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN) + +#define FWH_1MiB (FWH_F8_EN | FWH_F0_EN) + +#define FWH_0_5MiB (FWH_F8_EN) + + +struct esb2rom_window { + void __iomem* virt; + unsigned long phys; + unsigned long size; + struct list_head maps; + struct resource rsrc; + struct pci_dev *pdev; +}; + +struct esb2rom_map_info { + struct list_head list; + struct map_info map; + struct mtd_info *mtd; + struct resource rsrc; + char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; +}; + +static struct esb2rom_window esb2rom_window = { + .maps = LIST_HEAD_INIT(esb2rom_window.maps), +}; + +static void esb2rom_cleanup(struct esb2rom_window *window) +{ + struct esb2rom_map_info *map, *scratch; + u8 byte; + + /* Disable writes through the rom window */ + pci_read_config_byte(window->pdev, BIOS_CNTL, &byte); + pci_write_config_byte(window->pdev, BIOS_CNTL, + byte & ~BIOS_WRITE_ENABLE); + + /* Free all of the mtd devices */ + list_for_each_entry_safe(map, scratch, &window->maps, list) { + if (map->rsrc.parent) + release_resource(&map->rsrc); + del_mtd_device(map->mtd); + map_destroy(map->mtd); + list_del(&map->list); + kfree(map); + } + if (window->rsrc.parent) + release_resource(&window->rsrc); + if (window->virt) { + iounmap(window->virt); + window->virt = NULL; + window->phys = 0; + window->size = 0; + } + pci_dev_put(window->pdev); +} + +static int __devinit esb2rom_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; + struct esb2rom_window *window = &esb2rom_window; + struct esb2rom_map_info *map = NULL; + unsigned long map_top; + u8 byte; + u16 word; + + /* For now I just handle the ecb2 and I assume there + * are not a lot of resources up at the top of the address + * space. It is possible to handle other devices in the + * top 16MiB but it is very painful. Also since + * you can only really attach a FWH to an ICHX there + * a number of simplifications you can make. + * + * Also you can page firmware hubs if an 8MiB window isn't enough + * but don't currently handle that case either. + */ + window->pdev = pci_dev_get(pdev); + + /* RLG: experiment 2. Force the window registers to the widest values */ + +/* + pci_read_config_word(pdev, FWH_DEC_EN1, &word); + printk(KERN_DEBUG "Original FWH_DEC_EN1 : %x\n", word); + pci_write_config_byte(pdev, FWH_DEC_EN1, 0xff); + pci_read_config_byte(pdev, FWH_DEC_EN1, &byte); + printk(KERN_DEBUG "New FWH_DEC_EN1 : %x\n", byte); + + pci_read_config_byte(pdev, FWH_DEC_EN2, &byte); + printk(KERN_DEBUG "Original FWH_DEC_EN2 : %x\n", byte); + pci_write_config_byte(pdev, FWH_DEC_EN2, 0x0f); + pci_read_config_byte(pdev, FWH_DEC_EN2, &byte); + printk(KERN_DEBUG "New FWH_DEC_EN2 : %x\n", byte); +*/ + + /* Find a region continuous to the end of the ROM window */ + window->phys = 0; + pci_read_config_word(pdev, FWH_DEC_EN1, &word); + printk(KERN_DEBUG "pci_read_config_byte : %x\n", word); + + if ((word & FWH_8MiB) == FWH_8MiB) + window->phys = 0xff400000; + else if ((word & FWH_7MiB) == FWH_7MiB) + window->phys = 0xff500000; + else if ((word & FWH_6MiB) == FWH_6MiB) + window->phys = 0xff600000; + else if ((word & FWH_5MiB) == FWH_5MiB) + window->phys = 0xFF700000; + else if ((word & FWH_4MiB) == FWH_4MiB) + window->phys = 0xffc00000; + else if ((word & FWH_3_5MiB) == FWH_3_5MiB) + window->phys = 0xffc80000; + else if ((word & FWH_3MiB) == FWH_3MiB) + window->phys = 0xffd00000; + else if ((word & FWH_2_5MiB) == FWH_2_5MiB) + window->phys = 0xffd80000; + else if ((word & FWH_2MiB) == FWH_2MiB) + window->phys = 0xffe00000; + else if ((word & FWH_1_5MiB) == FWH_1_5MiB) + window->phys = 0xffe80000; + else if ((word & FWH_1MiB) == FWH_1MiB) + window->phys = 0xfff00000; + else if ((word & FWH_0_5MiB) == FWH_0_5MiB) + window->phys = 0xfff80000; + + /* reserved 0x0020 and 0x0010 */ + window->phys -= 0x400000UL; + window->size = (0xffffffffUL - window->phys) + 1UL; + + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, BIOS_CNTL, &byte); + if (!(byte & BIOS_WRITE_ENABLE) && (byte & (BIOS_LOCK_ENABLE))) { + /* The BIOS will generate an error if I enable + * this device, so don't even try. + */ + printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n"); + goto out; + } + pci_write_config_byte(pdev, BIOS_CNTL, byte | BIOS_WRITE_ENABLE); + + /* + * Try to reserve the window mem region. If this fails then + * it is likely due to the window being "reseved" by the BIOS. + */ + window->rsrc.name = MOD_NAME; + window->rsrc.start = window->phys; + window->rsrc.end = window->phys + window->size - 1; + window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &window->rsrc)) { + window->rsrc.parent = NULL; + printk(KERN_DEBUG MOD_NAME + ": %s(): Unable to register resource" + " 0x%.08llx-0x%.08llx - kernel bug?\n", + __func__, + (unsigned long long)window->rsrc.start, + (unsigned long long)window->rsrc.end); + } + + /* Map the firmware hub into my address space. */ + window->virt = ioremap_nocache(window->phys, window->size); + if (!window->virt) { + printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n", + window->phys, window->size); + goto out; + } + + /* Get the first address to look for an rom chip at */ + map_top = window->phys; + if ((window->phys & 0x3fffff) != 0) { + /* if not aligned on 4MiB, look 4MiB lower in address space */ + map_top = window->phys + 0x400000; + } +#if 1 + /* The probe sequence run over the firmware hub lock + * registers sets them to 0x7 (no access). + * (Insane hardware design, but most copied Intel's.) + * ==> Probe at most the last 4M of the address space. + */ + if (map_top < 0xffc00000) + map_top = 0xffc00000; +#endif + /* Loop through and look for rom chips */ + while ((map_top - 1) < 0xffffffffUL) { + struct cfi_private *cfi; + unsigned long offset; + int i; + + if (!map) + map = kmalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + printk(KERN_ERR MOD_NAME ": kmalloc failed"); + goto out; + } + memset(map, 0, sizeof(*map)); + INIT_LIST_HEAD(&map->list); + map->map.name = map->map_name; + map->map.phys = map_top; + offset = map_top - window->phys; + map->map.virt = (void __iomem *) + (((unsigned long)(window->virt)) + offset); + map->map.size = 0xffffffffUL - map_top + 1UL; + /* Set the name of the map to the address I am trying */ + sprintf(map->map_name, "%s @%08lx", + MOD_NAME, map->map.phys); + + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in-place programming + * needs to use a different method. + */ + for(map->map.bankwidth = 32; map->map.bankwidth; + map->map.bankwidth >>= 1) { + char **probe_type; + /* Skip bankwidths that are not supported */ + if (!map_bankwidth_supported(map->map.bankwidth)) + continue; + + /* Setup the map methods */ + simple_map_init(&map->map); + + /* Try all of the probe methods */ + probe_type = rom_probe_types; + for(; *probe_type; probe_type++) { + map->mtd = do_map_probe(*probe_type, &map->map); + if (map->mtd) + goto found; + } + } + map_top += ROM_PROBE_STEP_SIZE; + continue; + found: + /* Trim the size if we are larger than the map */ + if (map->mtd->size > map->map.size) { + printk(KERN_WARNING MOD_NAME + " rom(%u) larger than window(%lu). fixing...\n", + map->mtd->size, map->map.size); + map->mtd->size = map->map.size; + } + if (window->rsrc.parent) { + /* + * Registering the MTD device in iomem may not be possible + * if there is a BIOS "reserved" and BUSY range. If this + * fails then continue anyway. + */ + map->rsrc.name = map->map_name; + map->rsrc.start = map->map.phys; + map->rsrc.end = map->map.phys + map->mtd->size - 1; + map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&window->rsrc, &map->rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve MTD resource\n"); + map->rsrc.parent = NULL; + } + } + + /* Make the whole region visible in the map */ + map->map.virt = window->virt; + map->map.phys = window->phys; + cfi = map->map.fldrv_priv; + for(i = 0; i < cfi->numchips; i++) + cfi->chips[i].start += offset; + + /* Now that the mtd devices is complete claim and export it */ + map->mtd->owner = THIS_MODULE; + if (add_mtd_device(map->mtd)) { + map_destroy(map->mtd); + map->mtd = NULL; + goto out; + } + + /* Calculate the new value of map_top */ + map_top += map->mtd->size; + + /* File away the map structure */ + list_add(&map->list, &window->maps); + map = NULL; + } + + out: + /* Free any left over map structures */ + kfree(map); + + /* See if I have any map structures */ + if (list_empty(&window->maps)) { + esb2rom_cleanup(window); + return -ENODEV; + } + return 0; +} + +static void __devexit esb2rom_remove_one (struct pci_dev *pdev) +{ + struct esb2rom_window *window = &esb2rom_window; + esb2rom_cleanup(window); +} + +static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; + +#if 0 +MODULE_DEVICE_TABLE(pci, esb2rom_pci_tbl); + +static struct pci_driver esb2rom_driver = { + .name = MOD_NAME, + .id_table = esb2rom_pci_tbl, + .probe = esb2rom_init_one, + .remove = esb2rom_remove_one, +}; +#endif + +static int __init init_esb2rom(void) +{ + struct pci_dev *pdev; + struct pci_device_id *id; + int retVal; + + pdev = NULL; + for (id = esb2rom_pci_tbl; id->vendor; id++) { + printk(KERN_DEBUG "device id = %x\n", id->device); + pdev = pci_get_device(id->vendor, id->device, NULL); + if (pdev) { + printk(KERN_DEBUG "matched device = %x\n", id->device); + break; + } + } + if (pdev) { + printk(KERN_DEBUG "matched device id %x\n", id->device); + retVal = esb2rom_init_one(pdev, &esb2rom_pci_tbl[0]); + pci_dev_put(pdev); + printk(KERN_DEBUG "retVal = %d\n", retVal); + return retVal; + } + return -ENXIO; +#if 0 + return pci_register_driver(&esb2rom_driver); +#endif +} + +static void __exit cleanup_esb2rom(void) +{ + esb2rom_remove_one(esb2rom_window.pdev); +} + +module_init(init_esb2rom); +module_exit(cleanup_esb2rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lew Glendenning <lglendenning@lnxi.com>"); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ESB2 southbridge"); diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index c8db01b3e45..6946d802e6f 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -75,14 +75,12 @@ static int armflash_probe(struct platform_device *dev) int err; void __iomem *base; - info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL); + info = kzalloc(sizeof(struct armflash_info), GFP_KERNEL); if (!info) { err = -ENOMEM; goto out; } - memset(info, 0, sizeof(struct armflash_info)); - info->plat = plat; if (plat && plat->init) { err = plat->init(); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index f9e8e5bcbc3..9f53c655af3 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -20,6 +20,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/cfi.h> #include <linux/reboot.h> +#include <linux/err.h> #include <linux/kdev_t.h> #include <linux/root_dev.h> #include <asm/io.h> @@ -178,7 +179,7 @@ int nettel_eraseconfig(void) init_waitqueue_head(&wait_q); mtd = get_mtd_device(NULL, 2); - if (mtd) { + if (!IS_ERR(mtd)) { nettel_erase.mtd = mtd; nettel_erase.callback = nettel_erasecallback; nettel_erase.callback = NULL; @@ -471,7 +472,7 @@ out_unmap2: iounmap(nettel_amd_map.virt); return(rc); - + } /****************************************************************************/ diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index 418afffb2d8..e8d9ae53567 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c @@ -78,12 +78,10 @@ static int __devinit omapflash_probe(struct platform_device *pdev) struct resource *res = pdev->resource; unsigned long size = res->end - res->start + 1; - info = kmalloc(sizeof(struct omapflash_info), GFP_KERNEL); + info = kzalloc(sizeof(struct omapflash_info), GFP_KERNEL); if (!info) return -ENOMEM; - memset(info, 0, sizeof(struct omapflash_info)); - if (!request_mem_region(res->start, size, "flash")) { err = -EBUSY; goto out_free_info; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 995347b1beb..eaeb56a4070 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -735,11 +735,10 @@ static int pcmciamtd_probe(struct pcmcia_device *link) struct pcmciamtd_dev *dev; /* Create new memory card device */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; DEBUG(1, "dev=0x%p", dev); - memset(dev, 0, sizeof(*dev)); dev->p_dev = link; link->priv = dev; diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index d1717763f71..28c5ffd7523 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -89,15 +89,14 @@ static int physmap_flash_probe(struct platform_device *dev) return -ENODEV; printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n", - (unsigned long long)dev->resource->end - dev->resource->start + 1, + (unsigned long long)(dev->resource->end - dev->resource->start + 1), (unsigned long long)dev->resource->start); - info = kmalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); + info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); if (info == NULL) { err = -ENOMEM; goto err_out; } - memset(info, 0, sizeof(*info)); platform_set_drvdata(dev, info); diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c new file mode 100644 index 00000000000..7efe744ad31 --- /dev/null +++ b/drivers/mtd/maps/physmap_of.c @@ -0,0 +1,255 @@ +/* + * Normal mappings of chips in physical memory for OF devices + * + * Copyright (C) 2006 MontaVista Software Inc. + * Author: Vitaly Wool <vwool@ru.mvista.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/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/of_device.h> +#include <asm/of_platform.h> + +struct physmap_flash_info { + struct mtd_info *mtd; + struct map_info map; + struct resource *res; +#ifdef CONFIG_MTD_PARTITIONS + int nr_parts; + struct mtd_partition *parts; +#endif +}; + +static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; +#endif + +#ifdef CONFIG_MTD_PARTITIONS +static int parse_flash_partitions(struct device_node *node, + struct mtd_partition **parts) +{ + int i, plen, retval = -ENOMEM; + const u32 *part; + const char *name; + + part = get_property(node, "partitions", &plen); + if (part == NULL) + goto err; + + retval = plen / (2 * sizeof(u32)); + *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL); + if (*parts == NULL) { + printk(KERN_ERR "Can't allocate the flash partition data!\n"); + goto err; + } + + name = get_property(node, "partition-names", &plen); + + for (i = 0; i < retval; i++) { + (*parts)[i].offset = *part++; + (*parts)[i].size = *part & ~1; + if (*part++ & 1) /* bit 0 set signifies read only partition */ + (*parts)[i].mask_flags = MTD_WRITEABLE; + + if (name != NULL && plen > 0) { + int len = strlen(name) + 1; + + (*parts)[i].name = (char *)name; + plen -= len; + name += len; + } else + (*parts)[i].name = "unnamed"; + } +err: + return retval; +} +#endif + +static int of_physmap_remove(struct of_device *dev) +{ + struct physmap_flash_info *info; + + info = dev_get_drvdata(&dev->dev); + if (info == NULL) + return 0; + dev_set_drvdata(&dev->dev, NULL); + + if (info->mtd != NULL) { +#ifdef CONFIG_MTD_PARTITIONS + if (info->nr_parts) { + del_mtd_partitions(info->mtd); + kfree(info->parts); + } else { + del_mtd_device(info->mtd); + } +#else + del_mtd_device(info->mtd); +#endif + map_destroy(info->mtd); + } + + if (info->map.virt != NULL) + iounmap(info->map.virt); + + if (info->res != NULL) { + release_resource(info->res); + kfree(info->res); + } + + return 0; +} + +static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct device_node *dp = dev->node; + struct resource res; + struct physmap_flash_info *info; + const char **probe_type; + const char *of_probe; + const u32 *width; + int err; + + + if (of_address_to_resource(dp, 0, &res)) { + dev_err(&dev->dev, "Can't get the flash mapping!\n"); + err = -EINVAL; + goto err_out; + } + + dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n", + (unsigned long long)res.end - res.start + 1, + (unsigned long long)res.start); + + info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); + if (info == NULL) { + err = -ENOMEM; + goto err_out; + } + memset(info, 0, sizeof(*info)); + + dev_set_drvdata(&dev->dev, info); + + info->res = request_mem_region(res.start, res.end - res.start + 1, + dev->dev.bus_id); + if (info->res == NULL) { + dev_err(&dev->dev, "Could not reserve memory region\n"); + err = -ENOMEM; + goto err_out; + } + + width = get_property(dp, "bank-width", NULL); + if (width == NULL) { + dev_err(&dev->dev, "Can't get the flash bank width!\n"); + err = -EINVAL; + goto err_out; + } + + info->map.name = dev->dev.bus_id; + info->map.phys = res.start; + info->map.size = res.end - res.start + 1; + info->map.bankwidth = *width; + + info->map.virt = ioremap(info->map.phys, info->map.size); + if (info->map.virt == NULL) { + dev_err(&dev->dev, "Failed to ioremap flash region\n"); + err = EIO; + goto err_out; + } + + simple_map_init(&info->map); + + of_probe = get_property(dp, "probe-type", NULL); + if (of_probe == NULL) { + probe_type = rom_probe_types; + for (; info->mtd == NULL && *probe_type != NULL; probe_type++) + info->mtd = do_map_probe(*probe_type, &info->map); + } else if (!strcmp(of_probe, "CFI")) + info->mtd = do_map_probe("cfi_probe", &info->map); + else if (!strcmp(of_probe, "JEDEC")) + info->mtd = do_map_probe("jedec_probe", &info->map); + else { + if (strcmp(of_probe, "ROM")) + dev_dbg(&dev->dev, "map_probe: don't know probe type " + "'%s', mapping as rom\n"); + info->mtd = do_map_probe("mtd_rom", &info->map); + } + if (info->mtd == NULL) { + dev_err(&dev->dev, "map_probe failed\n"); + err = -ENXIO; + goto err_out; + } + info->mtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); + if (err > 0) { + add_mtd_partitions(info->mtd, info->parts, err); + } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) { + dev_info(&dev->dev, "Using OF partition information\n"); + add_mtd_partitions(info->mtd, info->parts, err); + info->nr_parts = err; + } else +#endif + + add_mtd_device(info->mtd); + return 0; + +err_out: + of_physmap_remove(dev); + return err; + + return 0; + + +} + +static struct of_device_id of_physmap_match[] = { + { + .type = "rom", + .compatible = "direct-mapped" + }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_physmap_match); + + +static struct of_platform_driver of_physmap_flash_driver = { + .name = "physmap-flash", + .match_table = of_physmap_match, + .probe = of_physmap_probe, + .remove = of_physmap_remove, +}; + +static int __init of_physmap_init(void) +{ + return of_register_platform_driver(&of_physmap_flash_driver); +} + +static void __exit of_physmap_exit(void) +{ + of_unregister_platform_driver(&of_physmap_flash_driver); +} + +module_init(of_physmap_init); +module_exit(of_physmap_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); +MODULE_DESCRIPTION("Configurable MTD map driver for OF"); diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 5d3c75451ca..2b6504ecbbd 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -147,14 +147,13 @@ static int platram_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; goto exit_error; } - memset(info, 0, sizeof(*info)); platform_set_drvdata(pdev, info); info->dev = &pdev->dev; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 950bf1c5784..f904e6bd02e 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -273,14 +273,12 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) /* * Allocate the map_info structs in one go. */ - info = kmalloc(size, GFP_KERNEL); + info = kzalloc(size, GFP_KERNEL); if (!info) { ret = -ENOMEM; goto out; } - memset(info, 0, size); - if (plat->init) { ret = plat->init(); if (ret) diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c index 58e5912bd38..9adc970e55e 100644 --- a/drivers/mtd/maps/tqm834x.c +++ b/drivers/mtd/maps/tqm834x.c @@ -132,20 +132,16 @@ static int __init init_tqm834x_mtd(void) pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx); - map_banks[idx] = - (struct map_info *)kmalloc(sizeof(struct map_info), - GFP_KERNEL); + map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); if (map_banks[idx] == NULL) { ret = -ENOMEM; goto error_mem; } - memset((void *)map_banks[idx], 0, sizeof(struct map_info)); - map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); + map_banks[idx]->name = kzalloc(16, GFP_KERNEL); if (map_banks[idx]->name == NULL) { ret = -ENOMEM; goto error_mem; } - memset((void *)map_banks[idx]->name, 0, 16); sprintf(map_banks[idx]->name, "TQM834x-%d", idx); map_banks[idx]->size = flash_size; diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 19578ba84ee..37e4ded9b60 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -134,14 +134,13 @@ int __init init_tqm_mtd(void) printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); - map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); + map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); if(map_banks[idx] == NULL) { ret = -ENOMEM; /* FIXME: What if some MTD devices were probed already? */ goto error_mem; } - memset((void *)map_banks[idx], 0, sizeof(struct map_info)); map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); if (!map_banks[idx]->name) { diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 178b53b56be..b879a66daa9 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -42,19 +42,20 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, unsigned long block, nsect; char *buf; - block = req->sector; - nsect = req->current_nr_sectors; + block = req->sector << 9 >> tr->blkshift; + nsect = req->current_nr_sectors << 9 >> tr->blkshift; + buf = req->buffer; if (!blk_fs_request(req)) return 0; - if (block + nsect > get_capacity(req->rq_disk)) + if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk)) return 0; switch(rq_data_dir(req)) { case READ: - for (; nsect > 0; nsect--, block++, buf += 512) + for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->readsect(dev, block, buf)) return 0; return 1; @@ -63,7 +64,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (!tr->writesect) return 0; - for (; nsect > 0; nsect--, block++, buf += 512) + for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->writesect(dev, block, buf)) return 0; return 1; @@ -297,7 +298,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) /* 2.5 has capacity in units of 512 bytes while still having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ - set_capacity(gd, (new->size * new->blksize) >> 9); + set_capacity(gd, (new->size * tr->blksize) >> 9); gd->private_data = new; new->blkcore_priv = gd; @@ -372,12 +373,10 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) if (!blktrans_notifier.list.next) register_mtd_user(&blktrans_notifier); - tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); + tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); if (!tr->blkcore_priv) return -ENOMEM; - memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv)); - mutex_lock(&mtd_table_mutex); ret = register_blkdev(tr->major, tr->name); @@ -401,6 +400,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) } tr->blkcore_priv->rq->queuedata = tr; + blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); + tr->blkshift = ffs(tr->blksize) - 1; ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL); if (ret < 0) { diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 04ed34694b1..952da30b174 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -278,11 +278,10 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) } /* OK, it's not open. Create cache info for it */ - mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); + mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); if (!mtdblk) return -ENOMEM; - memset(mtdblk, 0, sizeof(*mtdblk)); mtdblk->count = 1; mtdblk->mtd = mtd; @@ -339,16 +338,14 @@ static int mtdblock_flush(struct mtd_blktrans_dev *dev) static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { - struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); + struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return; - memset(dev, 0, sizeof(*dev)); - dev->mtd = mtd; dev->devnum = mtd->index; - dev->blksize = 512; + dev->size = mtd->size >> 9; dev->tr = tr; @@ -368,6 +365,7 @@ static struct mtd_blktrans_ops mtdblock_tr = { .name = "mtdblock", .major = 31, .part_bits = 0, + .blksize = 512, .open = mtdblock_open, .flush = mtdblock_flush, .release = mtdblock_release, diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 29563ed258a..f79dbb49b1a 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -33,16 +33,14 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev, static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { - struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); + struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return; - memset(dev, 0, sizeof(*dev)); - dev->mtd = mtd; dev->devnum = mtd->index; - dev->blksize = 512; + dev->size = mtd->size >> 9; dev->tr = tr; dev->readonly = 1; @@ -60,6 +58,7 @@ static struct mtd_blktrans_ops mtdblock_tr = { .name = "mtdblock", .major = 31, .part_bits = 0, + .blksize = 512, .readsect = mtdblock_readsect, .writesect = mtdblock_writesect, .add_mtd = mtdblock_add_mtd, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 5b6acfcb2b8..3013d0883b9 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -7,6 +7,7 @@ #include <linux/device.h> #include <linux/fs.h> +#include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> @@ -100,8 +101,8 @@ static int mtd_open(struct inode *inode, struct file *file) mtd = get_mtd_device(NULL, devnum); - if (!mtd) - return -ENODEV; + if (IS_ERR(mtd)) + return PTR_ERR(mtd); if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); @@ -431,7 +432,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if(!(file->f_mode & 2)) return -EPERM; - erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL); + erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL); if (!erase) ret = -ENOMEM; else { @@ -440,7 +441,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file, init_waitqueue_head(&waitq); - memset (erase,0,sizeof(struct erase_info)); if (copy_from_user(&erase->addr, argp, sizeof(struct erase_info_user))) { kfree(erase); @@ -499,13 +499,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (ret) return ret; - ops.len = buf.length; ops.ooblen = buf.length; ops.ooboffs = buf.start & (mtd->oobsize - 1); ops.datbuf = NULL; ops.mode = MTD_OOB_PLACE; - if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs)) + if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); @@ -520,7 +519,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, buf.start &= ~(mtd->oobsize - 1); ret = mtd->write_oob(mtd, buf.start, &ops); - if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen, + if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen, sizeof(uint32_t))) ret = -EFAULT; @@ -548,7 +547,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (ret) return ret; - ops.len = buf.length; ops.ooblen = buf.length; ops.ooboffs = buf.start & (mtd->oobsize - 1); ops.datbuf = NULL; @@ -564,10 +562,10 @@ static int mtd_ioctl(struct inode *inode, struct file *file, buf.start &= ~(mtd->oobsize - 1); ret = mtd->read_oob(mtd, buf.start, &ops); - if (put_user(ops.retlen, (uint32_t __user *)argp)) + if (put_user(ops.oobretlen, (uint32_t __user *)argp)) ret = -EFAULT; - else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf, - ops.retlen)) + else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf, + ops.oobretlen)) ret = -EFAULT; kfree(ops.oobbuf); @@ -616,6 +614,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos)); memcpy(&oi.oobfree, mtd->ecclayout->oobfree, sizeof(oi.oobfree)); + oi.eccbytes = mtd->ecclayout->eccbytes; if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo))) return -EFAULT; @@ -715,7 +714,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (!mtd->ecclayout) return -EOPNOTSUPP; - if (copy_to_user(argp, &mtd->ecclayout, + if (copy_to_user(argp, mtd->ecclayout, sizeof(struct nand_ecclayout))) return -EFAULT; break; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 1fea631b585..06902683bc2 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -247,7 +247,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) struct mtd_oob_ops devops = *ops; int i, err, ret = 0; - ops->retlen = 0; + ops->retlen = ops->oobretlen = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; @@ -263,6 +263,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) err = subdev->read_oob(subdev, from, &devops); ops->retlen += devops.retlen; + ops->oobretlen += devops.oobretlen; /* Save information about bitflips! */ if (unlikely(err)) { @@ -278,14 +279,18 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) return err; } - devops.len = ops->len - ops->retlen; - if (!devops.len) - return ret; - - if (devops.datbuf) + if (devops.datbuf) { + devops.len = ops->len - ops->retlen; + if (!devops.len) + return ret; devops.datbuf += devops.retlen; - if (devops.oobbuf) - devops.oobbuf += devops.ooblen; + } + if (devops.oobbuf) { + devops.ooblen = ops->ooblen - ops->oobretlen; + if (!devops.ooblen) + return ret; + devops.oobbuf += ops->oobretlen; + } from = 0; } @@ -321,14 +326,18 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) if (err) return err; - devops.len = ops->len - ops->retlen; - if (!devops.len) - return 0; - - if (devops.datbuf) + if (devops.datbuf) { + devops.len = ops->len - ops->retlen; + if (!devops.len) + return 0; devops.datbuf += devops.retlen; - if (devops.oobbuf) - devops.oobbuf += devops.ooblen; + } + if (devops.oobbuf) { + devops.ooblen = ops->ooblen - ops->oobretlen; + if (!devops.ooblen) + return 0; + devops.oobbuf += devops.oobretlen; + } to = 0; } return -EINVAL; @@ -699,14 +708,13 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c /* allocate the device structure */ size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); - concat = kmalloc(size, GFP_KERNEL); + concat = kzalloc(size, GFP_KERNEL); if (!concat) { printk ("memory allocation error while creating concatenated device \"%s\"\n", name); return NULL; } - memset(concat, 0, size); concat->subdev = (struct mtd_info **) (concat + 1); /* @@ -764,6 +772,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.ecc_stats.badblocks += subdev[i]->ecc_stats.badblocks; if (concat->mtd.writesize != subdev[i]->writesize || + concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.oobsize != subdev[i]->oobsize || concat->mtd.ecctype != subdev[i]->ecctype || concat->mtd.eccsize != subdev[i]->eccsize || diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c4d26de7434..7070110aba2 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -15,6 +15,7 @@ #include <linux/timer.h> #include <linux/major.h> #include <linux/fs.h> +#include <linux/err.h> #include <linux/ioctl.h> #include <linux/init.h> #include <linux/mtd/compatmac.h> @@ -192,14 +193,14 @@ int unregister_mtd_user (struct mtd_notifier *old) * Given a number and NULL address, return the num'th entry in the device * table, if any. Given an address and num == -1, search the device table * for a device with that address and return if it's still present. Given - * both, return the num'th driver only if its address matches. Return NULL - * if not. + * both, return the num'th driver only if its address matches. Return + * error code if not. */ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) { struct mtd_info *ret = NULL; - int i; + int i, err = -ENODEV; mutex_lock(&mtd_table_mutex); @@ -213,14 +214,73 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) ret = NULL; } - if (ret && !try_module_get(ret->owner)) - ret = NULL; + if (!ret) + goto out_unlock; + + if (!try_module_get(ret->owner)) + goto out_unlock; - if (ret) - ret->usecount++; + if (ret->get_device) { + err = ret->get_device(ret); + if (err) + goto out_put; + } + ret->usecount++; mutex_unlock(&mtd_table_mutex); return ret; + +out_put: + module_put(ret->owner); +out_unlock: + mutex_unlock(&mtd_table_mutex); + return ERR_PTR(err); +} + +/** + * get_mtd_device_nm - obtain a validated handle for an MTD device by + * device name + * @name: MTD device name to open + * + * This function returns MTD device description structure in case of + * success and an error code in case of failure. + */ + +struct mtd_info *get_mtd_device_nm(const char *name) +{ + int i, err = -ENODEV; + struct mtd_info *mtd = NULL; + + mutex_lock(&mtd_table_mutex); + + for (i = 0; i < MAX_MTD_DEVICES; i++) { + if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) { + mtd = mtd_table[i]; + break; + } + } + + if (!mtd) + goto out_unlock; + + if (!try_module_get(mtd->owner)) + goto out_unlock; + + if (mtd->get_device) { + err = mtd->get_device(mtd); + if (err) + goto out_put; + } + + mtd->usecount++; + mutex_unlock(&mtd_table_mutex); + return mtd; + +out_put: + module_put(mtd->owner); +out_unlock: + mutex_unlock(&mtd_table_mutex); + return ERR_PTR(err); } void put_mtd_device(struct mtd_info *mtd) @@ -229,6 +289,8 @@ void put_mtd_device(struct mtd_info *mtd) mutex_lock(&mtd_table_mutex); c = --mtd->usecount; + if (mtd->put_device) + mtd->put_device(mtd); mutex_unlock(&mtd_table_mutex); BUG_ON(c < 0); @@ -236,7 +298,7 @@ void put_mtd_device(struct mtd_info *mtd) } /* default_mtd_writev - default mtd writev method for MTD devices that - * dont implement their own + * don't implement their own */ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, @@ -264,13 +326,14 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, return ret; } -EXPORT_SYMBOL(add_mtd_device); -EXPORT_SYMBOL(del_mtd_device); -EXPORT_SYMBOL(get_mtd_device); -EXPORT_SYMBOL(put_mtd_device); -EXPORT_SYMBOL(register_mtd_user); -EXPORT_SYMBOL(unregister_mtd_user); -EXPORT_SYMBOL(default_mtd_writev); +EXPORT_SYMBOL_GPL(add_mtd_device); +EXPORT_SYMBOL_GPL(del_mtd_device); +EXPORT_SYMBOL_GPL(get_mtd_device); +EXPORT_SYMBOL_GPL(get_mtd_device_nm); +EXPORT_SYMBOL_GPL(put_mtd_device); +EXPORT_SYMBOL_GPL(register_mtd_user); +EXPORT_SYMBOL_GPL(unregister_mtd_user); +EXPORT_SYMBOL_GPL(default_mtd_writev); #ifdef CONFIG_PROC_FS diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 06a930372b7..bafd2fba87b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -94,7 +94,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, if (from >= mtd->size) return -EINVAL; - if (from + ops->len > mtd->size) + if (ops->datbuf && from + ops->len > mtd->size) return -EINVAL; res = part->master->read_oob(part->master, from + part->offset, ops); @@ -161,7 +161,7 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, if (to >= mtd->size) return -EINVAL; - if (to + ops->len > mtd->size) + if (ops->datbuf && to + ops->len > mtd->size) return -EINVAL; return part->master->write_oob(part->master, to + part->offset, ops); } @@ -323,14 +323,13 @@ int add_mtd_partitions(struct mtd_info *master, for (i = 0; i < nbparts; i++) { /* allocate the partition structure */ - slave = kmalloc (sizeof(*slave), GFP_KERNEL); + slave = kzalloc (sizeof(*slave), GFP_KERNEL); if (!slave) { printk ("memory allocation error while creating partitions for \"%s\"\n", master->name); del_mtd_partitions(master); return -ENOMEM; } - memset(slave, 0, sizeof(*slave)); list_add(&slave->list, &mtd_partitions); /* set up the MTD object for this partition */ @@ -341,6 +340,7 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.oobsize = master->oobsize; slave->mtd.ecctype = master->ecctype; slave->mtd.eccsize = master->eccsize; + slave->mtd.subpage_sft = master->subpage_sft; slave->mtd.name = parts[i].name; slave->mtd.bank_size = master->bank_size; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1831340e5f5..358f55a82db 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -90,6 +90,7 @@ config MTD_NAND_RTC_FROM4 depends on MTD_NAND && SH_SOLUTION_ENGINE select REED_SOLOMON select REED_SOLOMON_DEC8 + select BITREVERSE help This enables the driver for the Renesas Technology AG-AND flash interface board (FROM_BOARD4) @@ -132,6 +133,7 @@ config MTD_NAND_S3C2410_HWECC config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" depends on MTD_NAND && 44x + select MTD_NAND_ECC_SMC help NDFC Nand Flash Controllers are integrated in EP44x SoCs @@ -219,6 +221,13 @@ config MTD_NAND_SHARPSL tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" depends on MTD_NAND && ARCH_PXA +config MTD_NAND_CAFE + tristate "NAND support for OLPC CAFÉ chip" + depends on PCI + help + Use NAND flash attached to the CAFÉ chip designed for the $100 + laptop. + config MTD_NAND_CS553X tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH) @@ -232,6 +241,13 @@ config MTD_NAND_CS553X If you say "m", the module will be called "cs553x_nand.ko". +config MTD_NAND_AT91 + bool "Support for NAND Flash / SmartMedia on AT91" + depends on MTD_NAND && ARCH_AT91 + help + Enables support for NAND Flash / Smart Media Card interface + on Atmel AT91 processors. + config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" depends on MTD_NAND && MTD_PARTITIONS diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index f74759351c9..f7a53f0b701 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o +obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_TOTO) += toto.o @@ -22,5 +23,7 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o +obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o -nand-objs = nand_base.o nand_bbt.o +nand-objs := nand_base.o nand_bbt.o +cafe_nand-objs := cafe.o cafe_ecc.o diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c new file mode 100644 index 00000000000..14b80cc90a7 --- /dev/null +++ b/drivers/mtd/nand/at91_nand.c @@ -0,0 +1,223 @@ +/* + * drivers/mtd/nand/at91_nand.c + * + * Copyright (C) 2003 Rick Bronson + * + * Derived from drivers/mtd/nand/autcpu12.c + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * Derived from drivers/mtd/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include <asm/io.h> +#include <asm/sizes.h> + +#include <asm/hardware.h> +#include <asm/arch/board.h> +#include <asm/arch/gpio.h> + +struct at91_nand_host { + struct nand_chip nand_chip; + struct mtd_info mtd; + void __iomem *io_base; + struct at91_nand_data *board; +}; + +/* + * Hardware specific access to control-lines + */ +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 (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd, host->io_base + (1 << host->board->cle)); + else + writeb(cmd, host->io_base + (1 << host->board->ale)); +} + +/* + * Read the Device Ready pin. + */ +static int at91_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct at91_nand_host *host = nand_chip->priv; + + return at91_get_gpio_value(host->board->rdy_pin); +} + +/* + * 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); +} + +/* + * Probe for the NAND device. + */ +static int __init at91_nand_probe(struct platform_device *pdev) +{ + struct at91_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + int res; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; + int num_partitions = 0; +#endif + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); + return -ENOMEM; + } + + host->io_base = ioremap(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + if (host->io_base == NULL) { + printk(KERN_ERR "at91_nand: ioremap failed\n"); + kfree(host); + return -EIO; + } + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + host->board = pdev->dev.platform_data; + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = host->io_base; + nand_chip->IO_ADDR_W = host->io_base; + nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; + nand_chip->dev_ready = at91_nand_device_ready; + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ + nand_chip->chip_delay = 20; /* 20us command delay time */ + + if (host->board->bus_width_16) /* 16-bit bus width */ + nand_chip->options |= NAND_BUSWIDTH_16; + + platform_set_drvdata(pdev, host); + at91_nand_enable(host); + + if (host->board->det_pin) { + if (at91_get_gpio_value(host->board->det_pin)) { + printk ("No SmartMedia card inserted.\n"); + res = ENXIO; + goto out; + } + } + + /* Scan to find existance of the device */ + if (nand_scan(mtd, 1)) { + res = -ENXIO; + goto out; + } + +#ifdef CONFIG_MTD_PARTITIONS + if (host->board->partition_info) + partitions = host->board->partition_info(mtd->size, &num_partitions); + + if ((!partitions) || (num_partitions == 0)) { + printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); + res = ENXIO; + goto release; + } + + res = add_mtd_partitions(mtd, partitions, num_partitions); +#else + res = add_mtd_device(mtd); +#endif + + if (!res) + return res; + +release: + nand_release(mtd); +out: + at91_nand_disable(host); + platform_set_drvdata(pdev, NULL); + iounmap(host->io_base); + kfree(host); + return res; +} + +/* + * Remove a NAND device. + */ +static int __devexit at91_nand_remove(struct platform_device *pdev) +{ + struct at91_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + + at91_nand_disable(host); + + iounmap(host->io_base); + kfree(host); + + return 0; +} + +static struct platform_driver at91_nand_driver = { + .probe = at91_nand_probe, + .remove = at91_nand_remove, + .driver = { + .name = "at91_nand", + .owner = THIS_MODULE, + }, +}; + +static int __init at91_nand_init(void) +{ + return platform_driver_register(&at91_nand_driver); +} + + +static void __exit at91_nand_exit(void) +{ + platform_driver_unregister(&at91_nand_driver); +} + + +module_init(at91_nand_init); +module_exit(at91_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c new file mode 100644 index 00000000000..65f9bd3ceeb --- /dev/null +++ b/drivers/mtd/nand/cafe.c @@ -0,0 +1,771 @@ +/* + * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01 + * + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> + */ + +#define DEBUG + +#include <linux/device.h> +#undef DEBUG +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <asm/io.h> + +#define CAFE_NAND_CTRL1 0x00 +#define CAFE_NAND_CTRL2 0x04 +#define CAFE_NAND_CTRL3 0x08 +#define CAFE_NAND_STATUS 0x0c +#define CAFE_NAND_IRQ 0x10 +#define CAFE_NAND_IRQ_MASK 0x14 +#define CAFE_NAND_DATA_LEN 0x18 +#define CAFE_NAND_ADDR1 0x1c +#define CAFE_NAND_ADDR2 0x20 +#define CAFE_NAND_TIMING1 0x24 +#define CAFE_NAND_TIMING2 0x28 +#define CAFE_NAND_TIMING3 0x2c +#define CAFE_NAND_NONMEM 0x30 +#define CAFE_NAND_ECC_RESULT 0x3C +#define CAFE_NAND_DMA_CTRL 0x40 +#define CAFE_NAND_DMA_ADDR0 0x44 +#define CAFE_NAND_DMA_ADDR1 0x48 +#define CAFE_NAND_ECC_SYN01 0x50 +#define CAFE_NAND_ECC_SYN23 0x54 +#define CAFE_NAND_ECC_SYN45 0x58 +#define CAFE_NAND_ECC_SYN67 0x5c +#define CAFE_NAND_READ_DATA 0x1000 +#define CAFE_NAND_WRITE_DATA 0x2000 + +#define CAFE_GLOBAL_CTRL 0x3004 +#define CAFE_GLOBAL_IRQ 0x3008 +#define CAFE_GLOBAL_IRQ_MASK 0x300c +#define CAFE_NAND_RESET 0x3034 + +int cafe_correct_ecc(unsigned char *buf, + unsigned short *chk_syndrome_list); + +struct cafe_priv { + struct nand_chip nand; + struct pci_dev *pdev; + void __iomem *mmio; + uint32_t ctl1; + uint32_t ctl2; + int datalen; + int nr_data; + int data_pos; + int page_addr; + dma_addr_t dmaaddr; + unsigned char *dmabuf; +}; + +static int usedma = 1; +module_param(usedma, int, 0644); + +static int skipbbt = 0; +module_param(skipbbt, int, 0644); + +static int debug = 0; +module_param(debug, int, 0644); + +static int regdebug = 0; +module_param(regdebug, int, 0644); + +static int checkecc = 1; +module_param(checkecc, int, 0644); + +static int slowtiming = 0; +module_param(slowtiming, int, 0644); + +/* Hrm. Why isn't this already conditional on something in the struct device? */ +#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0) + +/* Make it easier to switch to PIO if we need to */ +#define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr) +#define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr) + +static int cafe_device_ready(struct mtd_info *mtd) +{ + struct cafe_priv *cafe = mtd->priv; + int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000); + uint32_t irqs = cafe_readl(cafe, NAND_IRQ); + + cafe_writel(cafe, irqs, NAND_IRQ); + + cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n", + result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ), + cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK)); + + return result; +} + + +static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct cafe_priv *cafe = mtd->priv; + + if (usedma) + memcpy(cafe->dmabuf + cafe->datalen, buf, len); + else + memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len); + + cafe->datalen += len; + + cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n", + len, cafe->datalen); +} + +static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct cafe_priv *cafe = mtd->priv; + + if (usedma) + memcpy(buf, cafe->dmabuf + cafe->datalen, len); + else + memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len); + + cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n", + len, cafe->datalen); + cafe->datalen += len; +} + +static uint8_t cafe_read_byte(struct mtd_info *mtd) +{ + struct cafe_priv *cafe = mtd->priv; + uint8_t d; + + cafe_read_buf(mtd, &d, 1); + cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d); + + return d; +} + +static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + struct cafe_priv *cafe = mtd->priv; + int adrbytes = 0; + uint32_t ctl1; + uint32_t doneint = 0x80000000; + + cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n", + command, column, page_addr); + + if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) { + /* Second half of a command we already calculated */ + cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2); + ctl1 = cafe->ctl1; + cafe->ctl2 &= ~(1<<30); + cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n", + cafe->ctl1, cafe->nr_data); + goto do_command; + } + /* Reset ECC engine */ + cafe_writel(cafe, 0, NAND_CTRL2); + + /* Emulate NAND_CMD_READOOB on large-page chips */ + if (mtd->writesize > 512 && + command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* FIXME: Do we need to send read command before sending data + for small-page chips, to position the buffer correctly? */ + + if (column != -1) { + cafe_writel(cafe, column, NAND_ADDR1); + adrbytes = 2; + if (page_addr != -1) + goto write_adr2; + } else if (page_addr != -1) { + cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1); + page_addr >>= 16; + write_adr2: + cafe_writel(cafe, page_addr, NAND_ADDR2); + adrbytes += 2; + if (mtd->size > mtd->writesize << 16) + adrbytes++; + } + + cafe->data_pos = cafe->datalen = 0; + + /* Set command valid bit */ + ctl1 = 0x80000000 | command; + + /* Set RD or WR bits as appropriate */ + if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) { + ctl1 |= (1<<26); /* rd */ + /* Always 5 bytes, for now */ + cafe->datalen = 4; + /* And one address cycle -- even for STATUS, since the controller doesn't work without */ + adrbytes = 1; + } else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || + command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) { + ctl1 |= 1<<26; /* rd */ + /* For now, assume just read to end of page */ + cafe->datalen = mtd->writesize + mtd->oobsize - column; + } else if (command == NAND_CMD_SEQIN) + ctl1 |= 1<<25; /* wr */ + + /* Set number of address bytes */ + if (adrbytes) + ctl1 |= ((adrbytes-1)|8) << 27; + + if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) { + /* Ignore the first command of a pair; the hardware + deals with them both at once, later */ + cafe->ctl1 = ctl1; + cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n", + cafe->ctl1, cafe->datalen); + return; + } + /* RNDOUT and READ0 commands need a following byte */ + if (command == NAND_CMD_RNDOUT) + cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2); + else if (command == NAND_CMD_READ0 && mtd->writesize > 512) + cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2); + + do_command: + cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n", + cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2)); + + /* NB: The datasheet lies -- we really should be subtracting 1 here */ + cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN); + cafe_writel(cafe, 0x90000000, NAND_IRQ); + if (usedma && (ctl1 & (3<<25))) { + uint32_t dmactl = 0xc0000000 + cafe->datalen; + /* If WR or RD bits set, set up DMA */ + if (ctl1 & (1<<26)) { + /* It's a read */ + dmactl |= (1<<29); + /* ... so it's done when the DMA is done, not just + the command. */ + doneint = 0x10000000; + } + cafe_writel(cafe, dmactl, NAND_DMA_CTRL); + } + cafe->datalen = 0; + + if (unlikely(regdebug)) { + int i; + printk("About to write command %08x to register 0\n", ctl1); + for (i=4; i< 0x5c; i+=4) + printk("Register %x: %08x\n", i, readl(cafe->mmio + i)); + } + + cafe_writel(cafe, ctl1, NAND_CTRL1); + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay(100); + + if (1) { + int c = 500000; + uint32_t irqs; + + while (c--) { + irqs = cafe_readl(cafe, NAND_IRQ); + if (irqs & doneint) + break; + udelay(1); + if (!(c % 100000)) + cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs); + cpu_relax(); + } + cafe_writel(cafe, doneint, NAND_IRQ); + cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n", + command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ)); + } + + WARN_ON(cafe->ctl2 & (1<<30)); + + switch (command) { + + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_RNDIN: + case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: + case NAND_CMD_RNDOUT: + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); + return; + } + nand_wait_ready(mtd); + cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); +} + +static void cafe_select_chip(struct mtd_info *mtd, int chipnr) +{ + //struct cafe_priv *cafe = mtd->priv; + // cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr); +} + +static int cafe_nand_interrupt(int irq, void *id) +{ + struct mtd_info *mtd = id; + struct cafe_priv *cafe = mtd->priv; + uint32_t irqs = cafe_readl(cafe, NAND_IRQ); + cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ); + if (!irqs) + return IRQ_NONE; + + cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ)); + return IRQ_HANDLED; +} + +static void cafe_nand_bug(struct mtd_info *mtd) +{ + BUG(); +} + +static int cafe_nand_write_oob(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int status = 0; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/* Don't use -- use nand_read_oob_std for now */ +static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return 1; +} +/** + * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * + * The hw generator calculates the error syndrome automatically. Therefor + * we need a special oob layout and handling. + */ +static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + struct cafe_priv *cafe = mtd->priv; + + cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n", + cafe_readl(cafe, NAND_ECC_RESULT), + cafe_readl(cafe, NAND_ECC_SYN01)); + + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) { + unsigned short syn[8]; + int i; + + for (i=0; i<8; i+=2) { + uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2)); + syn[i] = tmp & 0xfff; + syn[i+1] = (tmp >> 16) & 0xfff; + } + + if ((i = cafe_correct_ecc(buf, syn)) < 0) { + dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n", + cafe_readl(cafe, NAND_ADDR2) * 2048); + for (i=0; i< 0x5c; i+=4) + printk("Register %x: %08x\n", i, readl(cafe->mmio + i)); + mtd->ecc_stats.failed++; + } else { + dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i); + mtd->ecc_stats.corrected += i; + } + } + + + return 0; +} + +static struct nand_ecclayout cafe_oobinfo_2048 = { + .eccbytes = 14, + .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, + .oobfree = {{14, 50}} +}; + +/* Ick. The BBT code really ought to be able to work this bit out + for itself from the above, at least for the 2KiB case */ +static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' }; +static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' }; + +static uint8_t cafe_bbt_pattern_512[] = { 0xBB }; +static uint8_t cafe_mirror_pattern_512[] = { 0xBC }; + + +static struct nand_bbt_descr cafe_bbt_main_descr_2048 = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 14, + .len = 4, + .veroffs = 18, + .maxblocks = 4, + .pattern = cafe_bbt_pattern_2048 +}; + +static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 14, + .len = 4, + .veroffs = 18, + .maxblocks = 4, + .pattern = cafe_mirror_pattern_2048 +}; + +static struct nand_ecclayout cafe_oobinfo_512 = { + .eccbytes = 14, + .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, + .oobfree = {{14, 2}} +}; + +static struct nand_bbt_descr cafe_bbt_main_descr_512 = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 14, + .len = 1, + .veroffs = 15, + .maxblocks = 4, + .pattern = cafe_bbt_pattern_512 +}; + +static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 14, + .len = 1, + .veroffs = 15, + .maxblocks = 4, + .pattern = cafe_mirror_pattern_512 +}; + + +static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + struct cafe_priv *cafe = mtd->priv; + + chip->write_buf(mtd, buf, mtd->writesize); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Set up ECC autogeneration */ + cafe->ctl2 |= (1<<30); +} + +static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int page, int cached, int raw) +{ + int status; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + + if (unlikely(raw)) + chip->ecc.write_page_raw(mtd, chip, buf); + else + chip->ecc.write_page(mtd, chip, buf); + + /* + * Cached progamming disabled for now, Not sure if its worth the + * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + */ + cached = 0; + + if (!cached || !(chip->options & NAND_CACHEPRG)) { + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + /* + * See if operation failed and additional status checks are + * available + */ + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) + status = chip->errstat(mtd, chip, FL_WRITING, status, + page); + + if (status & NAND_STATUS_FAIL) + return -EIO; + } else { + chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + } + +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE + /* Send command to read back the data */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + if (chip->verify_buf(mtd, buf, mtd->writesize)) + return -EIO; +#endif + return 0; +} + +static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +{ + return 0; +} + +static int __devinit cafe_nand_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct mtd_info *mtd; + struct cafe_priv *cafe; + uint32_t ctrl; + int err = 0; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_master(pdev); + + mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL); + if (!mtd) { + dev_warn(&pdev->dev, "failed to alloc mtd_info\n"); + return -ENOMEM; + } + cafe = (void *)(&mtd[1]); + + mtd->priv = cafe; + mtd->owner = THIS_MODULE; + + cafe->pdev = pdev; + cafe->mmio = pci_iomap(pdev, 0, 0); + if (!cafe->mmio) { + dev_warn(&pdev->dev, "failed to iomap\n"); + err = -ENOMEM; + goto out_free_mtd; + } + cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers), + &cafe->dmaaddr, GFP_KERNEL); + if (!cafe->dmabuf) { + err = -ENOMEM; + goto out_ior; + } + cafe->nand.buffers = (void *)cafe->dmabuf + 2112; + + cafe->nand.cmdfunc = cafe_nand_cmdfunc; + cafe->nand.dev_ready = cafe_device_ready; + cafe->nand.read_byte = cafe_read_byte; + cafe->nand.read_buf = cafe_read_buf; + cafe->nand.write_buf = cafe_write_buf; + cafe->nand.select_chip = cafe_select_chip; + + cafe->nand.chip_delay = 0; + + /* Enable the following for a flash based bad block table */ + cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; + + if (skipbbt) { + cafe->nand.options |= NAND_SKIP_BBTSCAN; + cafe->nand.block_bad = cafe_nand_block_bad; + } + + /* Start off by resetting the NAND controller completely */ + cafe_writel(cafe, 1, NAND_RESET); + cafe_writel(cafe, 0, NAND_RESET); + + cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); + + /* Timings from Marvell's test code (not verified or calculated by us) */ + if (!slowtiming) { + cafe_writel(cafe, 0x01010a0a, NAND_TIMING1); + cafe_writel(cafe, 0x24121212, NAND_TIMING2); + cafe_writel(cafe, 0x11000000, NAND_TIMING3); + } else { + cafe_writel(cafe, 0xffffffff, NAND_TIMING1); + cafe_writel(cafe, 0xffffffff, NAND_TIMING2); + cafe_writel(cafe, 0xffffffff, NAND_TIMING3); + } + cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); + err = request_irq(pdev->irq, &cafe_nand_interrupt, SA_SHIRQ, "CAFE NAND", mtd); + if (err) { + dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); + + goto out_free_dma; + } +#if 1 + /* Disable master reset, enable NAND clock */ + ctrl = cafe_readl(cafe, GLOBAL_CTRL); + ctrl &= 0xffffeff0; + ctrl |= 0x00007000; + cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL); + cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL); + cafe_writel(cafe, 0, NAND_DMA_CTRL); + + cafe_writel(cafe, 0x7006, GLOBAL_CTRL); + cafe_writel(cafe, 0x700a, GLOBAL_CTRL); + + /* Set up DMA address */ + cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0); + if (sizeof(cafe->dmaaddr) > 4) + /* Shift in two parts to shut the compiler up */ + cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1); + else + cafe_writel(cafe, 0, NAND_DMA_ADDR1); + + cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n", + cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf); + + /* Enable NAND IRQ in global IRQ mask register */ + cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); + cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n", + cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK)); +#endif +#if 1 + mtd->writesize=2048; + mtd->oobsize = 0x40; + memset(cafe->dmabuf, 0x5a, 2112); + cafe->nand.cmdfunc(mtd, NAND_CMD_READID, 0, -1); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); +#endif +#if 0 + cafe->nand.cmdfunc(mtd, NAND_CMD_READ0, 0, 0); + // nand_wait_ready(mtd); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); + cafe->nand.read_byte(mtd); +#endif +#if 0 + writel(0x84600070, cafe->mmio); + udelay(10); + cafe_dev_dbg(&cafe->pdev->dev, "Status %x\n", cafe_readl(cafe, NAND_NONMEM)); +#endif + /* Scan to find existance of the device */ + if (nand_scan_ident(mtd, 1)) { + err = -ENXIO; + goto out_irq; + } + + cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */ + if (mtd->writesize == 2048) + cafe->ctl2 |= 1<<29; /* 2KiB page size */ + + /* Set up ECC according to the type of chip we found */ + if (mtd->writesize == 2048) { + cafe->nand.ecc.layout = &cafe_oobinfo_2048; + cafe->nand.bbt_td = &cafe_bbt_main_descr_2048; + cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048; + } else if (mtd->writesize == 512) { + cafe->nand.ecc.layout = &cafe_oobinfo_512; + cafe->nand.bbt_td = &cafe_bbt_main_descr_512; + cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512; + } else { + printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n", + mtd->writesize); + goto out_irq; + } + cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME; + cafe->nand.ecc.size = mtd->writesize; + cafe->nand.ecc.bytes = 14; + cafe->nand.ecc.hwctl = (void *)cafe_nand_bug; + cafe->nand.ecc.calculate = (void *)cafe_nand_bug; + cafe->nand.ecc.correct = (void *)cafe_nand_bug; + cafe->nand.write_page = cafe_nand_write_page; + cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel; + cafe->nand.ecc.write_oob = cafe_nand_write_oob; + cafe->nand.ecc.read_page = cafe_nand_read_page; + cafe->nand.ecc.read_oob = cafe_nand_read_oob; + + err = nand_scan_tail(mtd); + if (err) + goto out_irq; + + pci_set_drvdata(pdev, mtd); + add_mtd_device(mtd); + goto out; + + out_irq: + /* Disable NAND IRQ in global IRQ mask register */ + cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); + free_irq(pdev->irq, mtd); + out_free_dma: + dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); + out_ior: + pci_iounmap(pdev, cafe->mmio); + out_free_mtd: + kfree(mtd); + out: + return err; +} + +static void __devexit cafe_nand_remove(struct pci_dev *pdev) +{ + struct mtd_info *mtd = pci_get_drvdata(pdev); + struct cafe_priv *cafe = mtd->priv; + + del_mtd_device(mtd); + /* Disable NAND IRQ in global IRQ mask register */ + cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); + free_irq(pdev->irq, mtd); + nand_release(mtd); + pci_iounmap(pdev, cafe->mmio); + dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); + kfree(mtd); +} + +static struct pci_device_id cafe_nand_tbl[] = { + { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 } +}; + +MODULE_DEVICE_TABLE(pci, cafe_nand_tbl); + +static struct pci_driver cafe_nand_pci_driver = { + .name = "CAFÉ NAND", + .id_table = cafe_nand_tbl, + .probe = cafe_nand_probe, + .remove = __devexit_p(cafe_nand_remove), +#ifdef CONFIG_PMx + .suspend = cafe_nand_suspend, + .resume = cafe_nand_resume, +#endif +}; + +static int cafe_nand_init(void) +{ + return pci_register_driver(&cafe_nand_pci_driver); +} + +static void cafe_nand_exit(void) +{ + pci_unregister_driver(&cafe_nand_pci_driver); +} +module_init(cafe_nand_init); +module_exit(cafe_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); +MODULE_DESCRIPTION("NAND flash driver for OLPC CAFE chip"); + +/* Correct ECC for 2048 bytes of 0xff: + 41 a0 71 65 54 27 f3 93 ec a9 be ed 0b a1 */ + +/* dwmw2's B-test board, in case of completely screwing it: +Bad eraseblock 2394 at 0x12b40000 +Bad eraseblock 2627 at 0x14860000 +Bad eraseblock 3349 at 0x1a2a0000 +*/ diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c new file mode 100644 index 00000000000..1b9fa05a447 --- /dev/null +++ b/drivers/mtd/nand/cafe_ecc.c @@ -0,0 +1,1381 @@ +/* Error correction for CAFÉ NAND controller + * + * © 2006 Marvell, Inc. + * Author: Tom Chiou + * + * 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/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> + +static unsigned short gf4096_mul(unsigned short, unsigned short); +static unsigned short gf64_mul(unsigned short, unsigned short); +static unsigned short gf4096_inv(unsigned short); +static unsigned short err_pos(unsigned short); +static void find_4bit_err_coefs(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short *); +static void zero_4x5_col3(unsigned short[4][5]); +static void zero_4x5_col2(unsigned short[4][5]); +static void zero_4x5_col1(unsigned short[4][5]); +static void swap_4x5_rows(unsigned short[4][5], int, int, int); +static void swap_2x3_rows(unsigned short m[2][3]); +static void solve_4x5(unsigned short m[4][5], unsigned short *, int *); +static void sort_coefs(int *, unsigned short *, int); +static void find_4bit_err_pats(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short *); +static void find_3bit_err_coefs(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short, + unsigned short *); +static void zero_3x4_col2(unsigned short[3][4]); +static void zero_3x4_col1(unsigned short[3][4]); +static void swap_3x4_rows(unsigned short[3][4], int, int, int); +static void solve_3x4(unsigned short[3][4], unsigned short *, int *); +static void find_3bit_err_pats(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short, + unsigned short *); + +static void find_2bit_err_pats(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short *); +static void find_2x2_soln(unsigned short, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short, + unsigned short *); +static void solve_2x3(unsigned short[2][3], unsigned short *); +static int chk_no_err_only(unsigned short *, unsigned short *); +static int chk_1_err_only(unsigned short *, unsigned short *); +static int chk_2_err_only(unsigned short *, unsigned short *); +static int chk_3_err_only(unsigned short *, unsigned short *); +static int chk_4_err_only(unsigned short *, unsigned short *); + +static unsigned short gf64_mul(unsigned short a, unsigned short b) +{ + unsigned short tmp1, tmp2, tmp3, tmp4, tmp5; + unsigned short c_bit0, c_bit1, c_bit2, c_bit3, c_bit4, c_bit5, c; + + tmp1 = ((a) ^ (a >> 5)); + tmp2 = ((a >> 4) ^ (a >> 5)); + tmp3 = ((a >> 3) ^ (a >> 4)); + tmp4 = ((a >> 2) ^ (a >> 3)); + tmp5 = ((a >> 1) ^ (a >> 2)); + + c_bit0 = ((a & b) ^ ((a >> 5) & (b >> 1)) ^ ((a >> 4) & (b >> 2)) ^ + ((a >> 3) & (b >> 3)) ^ ((a >> 2) & (b >> 4)) ^ ((a >> 1) & (b >> 5))) & 0x1; + + c_bit1 = (((a >> 1) & b) ^ (tmp1 & (b >> 1)) ^ (tmp2 & (b >> 2)) ^ + (tmp3 & (b >> 3)) ^ (tmp4 & (b >> 4)) ^ (tmp5 & (b >> 5))) & 0x1; + + c_bit2 = (((a >> 2) & b) ^ ((a >> 1) & (b >> 1)) ^ (tmp1 & (b >> 2)) ^ + (tmp2 & (b >> 3)) ^ (tmp3 & (b >> 4)) ^ (tmp4 & (b >> 5))) & 0x1; + + c_bit3 = (((a >> 3) & b) ^ ((a >> 2) & (b >> 1)) ^ ((a >> 1) & (b >> 2)) ^ + (tmp1 & (b >> 3)) ^ (tmp2 & (b >> 4)) ^ (tmp3 & (b >> 5))) & 0x1; + + c_bit4 = (((a >> 4) & b) ^ ((a >> 3) & (b >> 1)) ^ ((a >> 2) & (b >> 2)) ^ + ((a >> 1) & (b >> 3)) ^ (tmp1 & (b >> 4)) ^ (tmp2 & (b >> 5))) & 0x1; + + c_bit5 = (((a >> 5) & b) ^ ((a >> 4) & (b >> 1)) ^ ((a >> 3) & (b >> 2)) ^ + ((a >> 2) & (b >> 3)) ^ ((a >> 1) & (b >> 4)) ^ (tmp1 & (b >> 5))) & 0x1; + + c = c_bit0 | (c_bit1 << 1) | (c_bit2 << 2) | (c_bit3 << 3) | (c_bit4 << 4) | (c_bit5 << 5); + + return c; +} + +static unsigned short gf4096_mul(unsigned short a, unsigned short b) +{ + unsigned short ah, al, bh, bl, alxah, blxbh, ablh, albl, ahbh, ahbhB, c; + + ah = (a >> 6) & 0x3f; + al = a & 0x3f; + bh = (b >> 6) & 0x3f; + bl = b & 0x3f; + alxah = al ^ ah; + blxbh = bl ^ bh; + + ablh = gf64_mul(alxah, blxbh); + albl = gf64_mul(al, bl); + ahbh = gf64_mul(ah, bh); + + ahbhB = ((ahbh & 0x1) << 5) | + ((ahbh & 0x20) >> 1) | + ((ahbh & 0x10) >> 1) | ((ahbh & 0x8) >> 1) | ((ahbh & 0x4) >> 1) | (((ahbh >> 1) ^ ahbh) & 0x1); + + c = ((ablh ^ albl) << 6) | (ahbhB ^ albl); + return c; +} + +static void find_2bit_err_pats(unsigned short s0, unsigned short s1, unsigned short r0, unsigned short r1, unsigned short *pats) +{ + find_2x2_soln(0x1, 0x1, r0, r1, s0, s1, pats); +} + +static void find_3bit_err_coefs(unsigned short s0, unsigned short s1, + unsigned short s2, unsigned short s3, unsigned short s4, unsigned short s5, unsigned short *coefs) +{ + unsigned short m[3][4]; + int row_order[3]; + + row_order[0] = 0; + row_order[1] = 1; + row_order[2] = 2; + m[0][0] = s2; + m[0][1] = s1; + m[0][2] = s0; + m[0][3] = s3; + m[1][0] = s3; + m[1][1] = s2; + m[1][2] = s1; + m[1][3] = s4; + m[2][0] = s4; + m[2][1] = s3; + m[2][2] = s2; + m[2][3] = s5; + + if (m[0][2] != 0x0) { + zero_3x4_col2(m); + } else if (m[1][2] != 0x0) { + swap_3x4_rows(m, 0, 1, 4); + zero_3x4_col2(m); + } else if (m[2][2] != 0x0) { + swap_3x4_rows(m, 0, 2, 4); + zero_3x4_col2(m); + } else { + printk(KERN_ERR "Error: find_3bit_err_coefs, s0,s1,s2 all zeros!\n"); + } + + if (m[1][1] != 0x0) { + zero_3x4_col1(m); + } else if (m[2][1] != 0x0) { + swap_3x4_rows(m, 1, 2, 4); + zero_3x4_col1(m); + } else { + printk(KERN_ERR "Error: find_3bit_err_coefs, cannot resolve col 1!\n"); + } + + /* solve coefs */ + solve_3x4(m, coefs, row_order); +} + +static void zero_3x4_col2(unsigned short m[3][4]) +{ + unsigned short minv1, minv2; + + minv1 = gf4096_mul(m[1][2], gf4096_inv(m[0][2])); + minv2 = gf4096_mul(m[2][2], gf4096_inv(m[0][2])); + m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1); + m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1); + m[1][3] = m[1][3] ^ gf4096_mul(m[0][3], minv1); + m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2); + m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2); + m[2][3] = m[2][3] ^ gf4096_mul(m[0][3], minv2); +} + +static void zero_3x4_col1(unsigned short m[3][4]) +{ + unsigned short minv; + minv = gf4096_mul(m[2][1], gf4096_inv(m[1][1])); + m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv); + m[2][3] = m[2][3] ^ gf4096_mul(m[1][3], minv); +} + +static void swap_3x4_rows(unsigned short m[3][4], int i, int j, int col_width) +{ + unsigned short tmp0; + int cnt; + for (cnt = 0; cnt < col_width; cnt++) { + tmp0 = m[i][cnt]; + m[i][cnt] = m[j][cnt]; + m[j][cnt] = tmp0; + } +} + +static void solve_3x4(unsigned short m[3][4], unsigned short *coefs, int *row_order) +{ + unsigned short tmp[3]; + tmp[0] = gf4096_mul(m[2][3], gf4096_inv(m[2][0])); + tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ m[1][3]), gf4096_inv(m[1][1])); + tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ gf4096_mul(tmp[1], m[0][1]) ^ m[0][3]), gf4096_inv(m[0][2])); + sort_coefs(row_order, tmp, 3); + coefs[0] = tmp[0]; + coefs[1] = tmp[1]; + coefs[2] = tmp[2]; +} + +static void find_3bit_err_pats(unsigned short s0, unsigned short s1, + unsigned short s2, unsigned short r0, + unsigned short r1, unsigned short r2, + unsigned short *pats) +{ + find_2x2_soln(r0 ^ r2, r1 ^ r2, + gf4096_mul(r0, r0 ^ r2), gf4096_mul(r1, r1 ^ r2), + gf4096_mul(s0, r2) ^ s1, gf4096_mul(s1, r2) ^ s2, pats); + pats[2] = s0 ^ pats[0] ^ pats[1]; +} + +static void find_4bit_err_coefs(unsigned short s0, unsigned short s1, + unsigned short s2, unsigned short s3, + unsigned short s4, unsigned short s5, + unsigned short s6, unsigned short s7, + unsigned short *coefs) +{ + unsigned short m[4][5]; + int row_order[4]; + + row_order[0] = 0; + row_order[1] = 1; + row_order[2] = 2; + row_order[3] = 3; + + m[0][0] = s3; + m[0][1] = s2; + m[0][2] = s1; + m[0][3] = s0; + m[0][4] = s4; + m[1][0] = s4; + m[1][1] = s3; + m[1][2] = s2; + m[1][3] = s1; + m[1][4] = s5; + m[2][0] = s5; + m[2][1] = s4; + m[2][2] = s3; + m[2][3] = s2; + m[2][4] = s6; + m[3][0] = s6; + m[3][1] = s5; + m[3][2] = s4; + m[3][3] = s3; + m[3][4] = s7; + + if (m[0][3] != 0x0) { + zero_4x5_col3(m); + } else if (m[1][3] != 0x0) { + swap_4x5_rows(m, 0, 1, 5); + zero_4x5_col3(m); + } else if (m[2][3] != 0x0) { + swap_4x5_rows(m, 0, 2, 5); + zero_4x5_col3(m); + } else if (m[3][3] != 0x0) { + swap_4x5_rows(m, 0, 3, 5); + zero_4x5_col3(m); + } else { + printk(KERN_ERR "Error: find_4bit_err_coefs, s0,s1,s2,s3 all zeros!\n"); + } + + if (m[1][2] != 0x0) { + zero_4x5_col2(m); + } else if (m[2][2] != 0x0) { + swap_4x5_rows(m, 1, 2, 5); + zero_4x5_col2(m); + } else if (m[3][2] != 0x0) { + swap_4x5_rows(m, 1, 3, 5); + zero_4x5_col2(m); + } else { + printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 2!\n"); + } + + if (m[2][1] != 0x0) { + zero_4x5_col1(m); + } else if (m[3][1] != 0x0) { + swap_4x5_rows(m, 2, 3, 5); + zero_4x5_col1(m); + } else { + printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 1!\n"); + } + + solve_4x5(m, coefs, row_order); +} + +static void zero_4x5_col3(unsigned short m[4][5]) +{ + unsigned short minv1, minv2, minv3; + + minv1 = gf4096_mul(m[1][3], gf4096_inv(m[0][3])); + minv2 = gf4096_mul(m[2][3], gf4096_inv(m[0][3])); + minv3 = gf4096_mul(m[3][3], gf4096_inv(m[0][3])); + + m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1); + m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1); + m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv1); + m[1][4] = m[1][4] ^ gf4096_mul(m[0][4], minv1); + m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2); + m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2); + m[2][2] = m[2][2] ^ gf4096_mul(m[0][2], minv2); + m[2][4] = m[2][4] ^ gf4096_mul(m[0][4], minv2); + m[3][0] = m[3][0] ^ gf4096_mul(m[0][0], minv3); + m[3][1] = m[3][1] ^ gf4096_mul(m[0][1], minv3); + m[3][2] = m[3][2] ^ gf4096_mul(m[0][2], minv3); + m[3][4] = m[3][4] ^ gf4096_mul(m[0][4], minv3); +} + +static void zero_4x5_col2(unsigned short m[4][5]) +{ + unsigned short minv2, minv3; + + minv2 = gf4096_mul(m[2][2], gf4096_inv(m[1][2])); + minv3 = gf4096_mul(m[3][2], gf4096_inv(m[1][2])); + + m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv2); + m[2][1] = m[2][1] ^ gf4096_mul(m[1][1], minv2); + m[2][4] = m[2][4] ^ gf4096_mul(m[1][4], minv2); + m[3][0] = m[3][0] ^ gf4096_mul(m[1][0], minv3); + m[3][1] = m[3][1] ^ gf4096_mul(m[1][1], minv3); + m[3][4] = m[3][4] ^ gf4096_mul(m[1][4], minv3); +} + +static void zero_4x5_col1(unsigned short m[4][5]) +{ + unsigned short minv; + + minv = gf4096_mul(m[3][1], gf4096_inv(m[2][1])); + + m[3][0] = m[3][0] ^ gf4096_mul(m[2][0], minv); + m[3][4] = m[3][4] ^ gf4096_mul(m[2][4], minv); +} + +static void swap_4x5_rows(unsigned short m[4][5], int i, int j, int col_width) +{ + unsigned short tmp0; + int cnt; + + for (cnt = 0; cnt < col_width; cnt++) { + tmp0 = m[i][cnt]; + m[i][cnt] = m[j][cnt]; + m[j][cnt] = tmp0; + } +} + +static void solve_4x5(unsigned short m[4][5], unsigned short *coefs, int *row_order) +{ + unsigned short tmp[4]; + + tmp[0] = gf4096_mul(m[3][4], gf4096_inv(m[3][0])); + tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[2][0]) ^ m[2][4]), gf4096_inv(m[2][1])); + tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ gf4096_mul(tmp[1], m[1][1]) ^ m[1][4]), gf4096_inv(m[1][2])); + tmp[3] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ + gf4096_mul(tmp[1], m[0][1]) ^ gf4096_mul(tmp[2], m[0][2]) ^ m[0][4]), gf4096_inv(m[0][3])); + sort_coefs(row_order, tmp, 4); + coefs[0] = tmp[0]; + coefs[1] = tmp[1]; + coefs[2] = tmp[2]; + coefs[3] = tmp[3]; +} + +static void sort_coefs(int *order, unsigned short *soln, int len) +{ + int cnt, start_cnt, least_ord, least_cnt; + unsigned short tmp0; + for (start_cnt = 0; start_cnt < len; start_cnt++) { + for (cnt = start_cnt; cnt < len; cnt++) { + if (cnt == start_cnt) { + least_ord = order[cnt]; + least_cnt = start_cnt; + } else { + if (least_ord > order[cnt]) { + least_ord = order[cnt]; + least_cnt = cnt; + } + } + } + if (least_cnt != start_cnt) { + tmp0 = order[least_cnt]; + order[least_cnt] = order[start_cnt]; + order[start_cnt] = tmp0; + tmp0 = soln[least_cnt]; + soln[least_cnt] = soln[start_cnt]; + soln[start_cnt] = tmp0; + } + } +} + +static void find_4bit_err_pats(unsigned short s0, unsigned short s1, + unsigned short s2, unsigned short s3, + unsigned short z1, unsigned short z2, + unsigned short z3, unsigned short z4, + unsigned short *pats) +{ + unsigned short z4_z1, z3z4_z3z3, z4_z2, s0z4_s1, z1z4_z1z1, + z4_z3, z2z4_z2z2, s1z4_s2, z3z3z4_z3z3z3, z1z1z4_z1z1z1, z2z2z4_z2z2z2, s2z4_s3; + unsigned short tmp0, tmp1, tmp2, tmp3; + + z4_z1 = z4 ^ z1; + z3z4_z3z3 = gf4096_mul(z3, z4) ^ gf4096_mul(z3, z3); + z4_z2 = z4 ^ z2; + s0z4_s1 = gf4096_mul(s0, z4) ^ s1; + z1z4_z1z1 = gf4096_mul(z1, z4) ^ gf4096_mul(z1, z1); + z4_z3 = z4 ^ z3; + z2z4_z2z2 = gf4096_mul(z2, z4) ^ gf4096_mul(z2, z2); + s1z4_s2 = gf4096_mul(s1, z4) ^ s2; + z3z3z4_z3z3z3 = gf4096_mul(gf4096_mul(z3, z3), z4) ^ gf4096_mul(gf4096_mul(z3, z3), z3); + z1z1z4_z1z1z1 = gf4096_mul(gf4096_mul(z1, z1), z4) ^ gf4096_mul(gf4096_mul(z1, z1), z1); + z2z2z4_z2z2z2 = gf4096_mul(gf4096_mul(z2, z2), z4) ^ gf4096_mul(gf4096_mul(z2, z2), z2); + s2z4_s3 = gf4096_mul(s2, z4) ^ s3; + + //find err pat 0,1 + find_2x2_soln(gf4096_mul(z4_z1, z3z4_z3z3) ^ + gf4096_mul(z1z4_z1z1, z4_z3), gf4096_mul(z4_z2, + z3z4_z3z3) ^ + gf4096_mul(z2z4_z2z2, z4_z3), gf4096_mul(z1z4_z1z1, + z3z3z4_z3z3z3) ^ + gf4096_mul(z1z1z4_z1z1z1, z3z4_z3z3), + gf4096_mul(z2z4_z2z2, + z3z3z4_z3z3z3) ^ gf4096_mul(z2z2z4_z2z2z2, + z3z4_z3z3), + gf4096_mul(s0z4_s1, z3z4_z3z3) ^ gf4096_mul(s1z4_s2, + z4_z3), + gf4096_mul(s1z4_s2, z3z3z4_z3z3z3) ^ gf4096_mul(s2z4_s3, z3z4_z3z3), pats); + tmp0 = pats[0]; + tmp1 = pats[1]; + tmp2 = pats[0] ^ pats[1] ^ s0; + tmp3 = gf4096_mul(pats[0], z1) ^ gf4096_mul(pats[1], z2) ^ s1; + + //find err pat 2,3 + find_2x2_soln(0x1, 0x1, z3, z4, tmp2, tmp3, pats); + pats[2] = pats[0]; + pats[3] = pats[1]; + pats[0] = tmp0; + pats[1] = tmp1; +} + +static void find_2x2_soln(unsigned short c00, unsigned short c01, + unsigned short c10, unsigned short c11, + unsigned short lval0, unsigned short lval1, + unsigned short *soln) +{ + unsigned short m[2][3]; + m[0][0] = c00; + m[0][1] = c01; + m[0][2] = lval0; + m[1][0] = c10; + m[1][1] = c11; + m[1][2] = lval1; + + if (m[0][1] != 0x0) { + /* */ + } else if (m[1][1] != 0x0) { + swap_2x3_rows(m); + } else { + printk(KERN_ERR "Warning: find_2bit_err_coefs, s0,s1 all zeros!\n"); + } + + solve_2x3(m, soln); +} + +static void swap_2x3_rows(unsigned short m[2][3]) +{ + unsigned short tmp0; + int cnt; + + for (cnt = 0; cnt < 3; cnt++) { + tmp0 = m[0][cnt]; + m[0][cnt] = m[1][cnt]; + m[1][cnt] = tmp0; + } +} + +static void solve_2x3(unsigned short m[2][3], unsigned short *coefs) +{ + unsigned short minv; + + minv = gf4096_mul(m[1][1], gf4096_inv(m[0][1])); + m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv); + m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv); + coefs[0] = gf4096_mul(m[1][2], gf4096_inv(m[1][0])); + coefs[1] = gf4096_mul((gf4096_mul(coefs[0], m[0][0]) ^ m[0][2]), gf4096_inv(m[0][1])); +} + +static unsigned char gf64_inv[64] = { + 0, 1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25, + 61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45, 6, + 63, 2, 27, 21, 56, 9, 50, 19, 13, 47, 48, 5, 7, 30, 12, 41, + 42, 4, 38, 18, 10, 29, 17, 60, 36, 8, 59, 58, 55, 16, 3, 32 +}; + +static unsigned short gf4096_inv(unsigned short din) +{ + unsigned short alahxal, ah2B, deno, inv, bl, bh; + unsigned short ah, al, ahxal; + unsigned short dout; + + ah = (din >> 6) & 0x3f; + al = din & 0x3f; + ahxal = ah ^ al; + ah2B = (((ah ^ (ah >> 3)) & 0x1) << 5) | + ((ah >> 1) & 0x10) | + ((((ah >> 5) ^ (ah >> 2)) & 0x1) << 3) | + ((ah >> 2) & 0x4) | ((((ah >> 4) ^ (ah >> 1)) & 0x1) << 1) | (ah & 0x1); + alahxal = gf64_mul(ahxal, al); + deno = alahxal ^ ah2B; + inv = gf64_inv[deno]; + bl = gf64_mul(inv, ahxal); + bh = gf64_mul(inv, ah); + dout = ((bh & 0x3f) << 6) | (bl & 0x3f); + return (((bh & 0x3f) << 6) | (bl & 0x3f)); +} + +static unsigned short err_pos_lut[4096] = { + 0xfff, 0x000, 0x451, 0xfff, 0xfff, 0x3cf, 0xfff, 0x041, + 0xfff, 0xfff, 0xfff, 0xfff, 0x28a, 0xfff, 0x492, 0xfff, + 0x145, 0xfff, 0xfff, 0x514, 0xfff, 0x082, 0xfff, 0xfff, + 0xfff, 0x249, 0x38e, 0x410, 0xfff, 0x104, 0x208, 0x1c7, + 0xfff, 0xfff, 0xfff, 0xfff, 0x2cb, 0xfff, 0xfff, 0xfff, + 0x0c3, 0x34d, 0x4d3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x186, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x30c, 0x555, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x166, 0xfff, 0xfff, 0xfff, 0xfff, + 0x385, 0x14e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e1, + 0xfff, 0xfff, 0xfff, 0xfff, 0x538, 0xfff, 0x16d, 0xfff, + 0xfff, 0xfff, 0x45b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x29c, 0x2cc, 0x30b, 0x2b3, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0b3, 0xfff, 0x2f7, + 0xfff, 0x32b, 0xfff, 0xfff, 0xfff, 0xfff, 0x0a7, 0xfff, + 0xfff, 0x2da, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x07e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x11c, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x22f, 0xfff, 0x1f4, 0xfff, 0xfff, + 0x2b0, 0x504, 0xfff, 0x114, 0xfff, 0xfff, 0xfff, 0x21d, + 0xfff, 0xfff, 0xfff, 0xfff, 0x00d, 0x3c4, 0x340, 0x10f, + 0xfff, 0xfff, 0x266, 0x02e, 0xfff, 0xfff, 0xfff, 0x4f8, + 0x337, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x07b, 0x168, 0xfff, 0xfff, 0x0fe, + 0xfff, 0xfff, 0x51a, 0xfff, 0x458, 0xfff, 0x36d, 0xfff, + 0xfff, 0xfff, 0xfff, 0x073, 0x37d, 0x415, 0x550, 0xfff, + 0xfff, 0xfff, 0x23b, 0x4b4, 0xfff, 0xfff, 0xfff, 0x1a1, + 0xfff, 0xfff, 0x3aa, 0xfff, 0x117, 0x04d, 0x341, 0xfff, + 0xfff, 0xfff, 0xfff, 0x518, 0x03e, 0x0f2, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x363, 0xfff, 0x0b9, 0xfff, 0xfff, + 0x241, 0xfff, 0xfff, 0x049, 0xfff, 0xfff, 0xfff, 0xfff, + 0x15f, 0x52d, 0xfff, 0xfff, 0xfff, 0x29e, 0xfff, 0xfff, + 0xfff, 0xfff, 0x4cf, 0x0fc, 0xfff, 0x36f, 0x3d3, 0xfff, + 0x228, 0xfff, 0xfff, 0x45e, 0xfff, 0xfff, 0xfff, 0xfff, + 0x238, 0xfff, 0xfff, 0xfff, 0xfff, 0x47f, 0xfff, 0xfff, + 0x43a, 0x265, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e8, + 0xfff, 0xfff, 0x01a, 0xfff, 0xfff, 0xfff, 0xfff, 0x21e, + 0x1fc, 0x40b, 0xfff, 0xfff, 0xfff, 0x2d0, 0x159, 0xfff, + 0xfff, 0x313, 0xfff, 0xfff, 0x05c, 0x4cc, 0xfff, 0xfff, + 0x0f6, 0x3d5, 0xfff, 0xfff, 0xfff, 0x54f, 0xfff, 0xfff, + 0xfff, 0x172, 0x1e4, 0x07c, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x53c, 0x1ad, 0x535, + 0x19b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x092, 0xfff, 0x2be, 0xfff, 0xfff, 0x482, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0e6, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x476, 0xfff, 0x51d, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x342, 0x2b5, 0x22e, 0x09a, 0xfff, 0x08d, + 0x44f, 0x3ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d1, 0xfff, + 0xfff, 0x543, 0xfff, 0x48f, 0xfff, 0x3d2, 0xfff, 0x0d5, + 0x113, 0x0ec, 0x427, 0xfff, 0xfff, 0xfff, 0x4c4, 0xfff, + 0xfff, 0x50a, 0xfff, 0x144, 0xfff, 0x105, 0x39f, 0x294, + 0x164, 0xfff, 0x31a, 0xfff, 0xfff, 0x49a, 0xfff, 0x130, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x1be, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x49e, 0x371, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x0e8, 0x49c, 0x0f4, 0xfff, + 0x338, 0x1a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x36c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x1ae, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x31b, 0xfff, 0xfff, 0x2dd, 0x522, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f4, + 0x3c6, 0x30d, 0xfff, 0xfff, 0xfff, 0xfff, 0x34c, 0x18f, + 0x30a, 0xfff, 0x01f, 0x079, 0xfff, 0xfff, 0x54d, 0x46b, + 0x28c, 0x37f, 0xfff, 0xfff, 0xfff, 0xfff, 0x355, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x14f, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x359, 0x3fe, 0x3c5, 0xfff, 0xfff, + 0xfff, 0xfff, 0x423, 0xfff, 0xfff, 0x34a, 0x22c, 0xfff, + 0x25a, 0xfff, 0xfff, 0x4ad, 0xfff, 0x28d, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x547, 0xfff, 0xfff, 0xfff, 0xfff, + 0x2e2, 0xfff, 0xfff, 0x1d5, 0xfff, 0x2a8, 0xfff, 0xfff, + 0x03f, 0xfff, 0xfff, 0xfff, 0xfff, 0x3eb, 0x0fa, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x55b, 0xfff, + 0x08e, 0xfff, 0x3ae, 0xfff, 0x3a4, 0xfff, 0x282, 0x158, + 0xfff, 0x382, 0xfff, 0xfff, 0x499, 0xfff, 0xfff, 0x08a, + 0xfff, 0xfff, 0xfff, 0x456, 0x3be, 0xfff, 0x1e2, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x559, 0xfff, 0x1a0, 0xfff, + 0xfff, 0x0b4, 0xfff, 0xfff, 0xfff, 0x2df, 0xfff, 0xfff, + 0xfff, 0x07f, 0x4f5, 0xfff, 0xfff, 0x27c, 0x133, 0x017, + 0xfff, 0x3fd, 0xfff, 0xfff, 0xfff, 0x44d, 0x4cd, 0x17a, + 0x0d7, 0x537, 0xfff, 0xfff, 0x353, 0xfff, 0xfff, 0x351, + 0x366, 0xfff, 0x44a, 0xfff, 0x1a6, 0xfff, 0xfff, 0xfff, + 0x291, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1e3, + 0xfff, 0xfff, 0xfff, 0xfff, 0x389, 0xfff, 0x07a, 0xfff, + 0x1b6, 0x2ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x24e, 0x074, + 0xfff, 0xfff, 0x3dc, 0xfff, 0x4e3, 0xfff, 0xfff, 0xfff, + 0xfff, 0x4eb, 0xfff, 0xfff, 0x3b8, 0x4de, 0xfff, 0x19c, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x262, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x076, 0x4e8, 0x3da, + 0xfff, 0x531, 0xfff, 0xfff, 0x14a, 0xfff, 0x0a2, 0x433, + 0x3df, 0x1e9, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e7, 0x285, + 0x2d8, 0xfff, 0xfff, 0xfff, 0x349, 0x18d, 0x098, 0xfff, + 0x0df, 0x4bf, 0xfff, 0xfff, 0x0b2, 0xfff, 0x346, 0x24d, + 0xfff, 0xfff, 0xfff, 0x24f, 0x4fa, 0x2f9, 0xfff, 0xfff, + 0x3c9, 0xfff, 0x2b4, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x056, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x179, 0xfff, 0x0e9, 0x3f0, 0x33d, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x1fd, 0xfff, 0xfff, 0x526, 0xfff, + 0xfff, 0xfff, 0x53d, 0xfff, 0xfff, 0xfff, 0x170, 0x331, + 0xfff, 0x068, 0xfff, 0xfff, 0xfff, 0x3f7, 0xfff, 0x3d8, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x09f, 0x556, 0xfff, 0xfff, 0x02d, 0xfff, 0xfff, + 0x553, 0xfff, 0xfff, 0xfff, 0x1f0, 0xfff, 0xfff, 0x4d6, + 0x41e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d5, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x248, 0xfff, 0xfff, 0xfff, 0x0a3, + 0xfff, 0x217, 0xfff, 0xfff, 0xfff, 0x4f1, 0x209, 0xfff, + 0xfff, 0x475, 0x234, 0x52b, 0x398, 0xfff, 0x08b, 0xfff, + 0xfff, 0xfff, 0xfff, 0x2c2, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x268, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x4a3, 0xfff, 0x0aa, 0xfff, 0x1d9, 0xfff, 0xfff, + 0xfff, 0xfff, 0x155, 0xfff, 0xfff, 0xfff, 0xfff, 0x0bf, + 0x539, 0xfff, 0xfff, 0x2f1, 0x545, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x2a7, 0x06f, 0xfff, 0x378, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x25e, 0xfff, + 0xfff, 0xfff, 0xfff, 0x15d, 0x02a, 0xfff, 0xfff, 0x0bc, + 0x235, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x150, 0xfff, 0x1a9, 0xfff, 0xfff, 0xfff, 0xfff, 0x381, + 0xfff, 0x04e, 0x270, 0x13f, 0xfff, 0xfff, 0x405, 0xfff, + 0x3cd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x2ef, 0xfff, 0x06a, 0xfff, 0xfff, 0xfff, 0x34f, + 0x212, 0xfff, 0xfff, 0x0e2, 0xfff, 0x083, 0x298, 0xfff, + 0xfff, 0xfff, 0x0c2, 0xfff, 0xfff, 0x52e, 0xfff, 0x488, + 0xfff, 0xfff, 0xfff, 0x36b, 0xfff, 0xfff, 0xfff, 0x442, + 0x091, 0xfff, 0x41c, 0xfff, 0xfff, 0x3a5, 0xfff, 0x4e6, + 0xfff, 0xfff, 0x40d, 0x31d, 0xfff, 0xfff, 0xfff, 0x4c1, + 0x053, 0xfff, 0x418, 0x13c, 0xfff, 0x350, 0xfff, 0x0ae, + 0xfff, 0xfff, 0x41f, 0xfff, 0x470, 0xfff, 0x4ca, 0xfff, + 0xfff, 0xfff, 0x02b, 0x450, 0xfff, 0x1f8, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x293, 0xfff, + 0xfff, 0xfff, 0xfff, 0x411, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x0b8, 0xfff, 0xfff, 0xfff, + 0x3e1, 0xfff, 0xfff, 0xfff, 0xfff, 0x43c, 0xfff, 0x2b2, + 0x2ab, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ec, + 0xfff, 0xfff, 0xfff, 0x3f8, 0x034, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x11a, 0xfff, 0x541, 0x45c, 0x134, + 0x1cc, 0xfff, 0xfff, 0xfff, 0x469, 0xfff, 0xfff, 0x44b, + 0x161, 0xfff, 0xfff, 0xfff, 0x055, 0xfff, 0xfff, 0xfff, + 0xfff, 0x307, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d1, 0xfff, + 0xfff, 0xfff, 0x124, 0x37b, 0x26b, 0x336, 0xfff, 0xfff, + 0x2e4, 0x3cb, 0xfff, 0xfff, 0x0f8, 0x3c8, 0xfff, 0xfff, + 0xfff, 0x461, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4b5, + 0x2cf, 0xfff, 0xfff, 0xfff, 0x20f, 0xfff, 0x35a, 0xfff, + 0x490, 0xfff, 0x185, 0xfff, 0xfff, 0xfff, 0xfff, 0x42e, + 0xfff, 0xfff, 0xfff, 0xfff, 0x54b, 0xfff, 0xfff, 0xfff, + 0x146, 0xfff, 0x412, 0xfff, 0xfff, 0xfff, 0x1ff, 0xfff, + 0xfff, 0x3e0, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d5, 0xfff, + 0x4df, 0x505, 0xfff, 0x413, 0xfff, 0x1a5, 0xfff, 0x3b2, + 0xfff, 0xfff, 0xfff, 0x35b, 0xfff, 0x116, 0xfff, 0xfff, + 0x171, 0x4d0, 0xfff, 0x154, 0x12d, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x468, 0x4db, 0xfff, + 0xfff, 0x1df, 0xfff, 0xfff, 0xfff, 0xfff, 0x05a, 0xfff, + 0x0f1, 0x403, 0xfff, 0x22b, 0x2e0, 0xfff, 0xfff, 0xfff, + 0x2b7, 0x373, 0xfff, 0xfff, 0xfff, 0xfff, 0x13e, 0xfff, + 0xfff, 0xfff, 0x0d0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x329, 0x1d2, 0x3fa, 0x047, 0xfff, 0x2f2, 0xfff, 0xfff, + 0x141, 0x0ac, 0x1d7, 0xfff, 0x07d, 0xfff, 0xfff, 0xfff, + 0x1c1, 0xfff, 0x487, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x045, 0xfff, 0xfff, 0xfff, 0xfff, + 0x288, 0x0cd, 0xfff, 0xfff, 0xfff, 0xfff, 0x226, 0x1d8, + 0xfff, 0x153, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4cb, + 0x528, 0xfff, 0xfff, 0xfff, 0x20a, 0x343, 0x3a1, 0xfff, + 0xfff, 0xfff, 0x2d7, 0x2d3, 0x1aa, 0x4c5, 0xfff, 0xfff, + 0xfff, 0x42b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x3e9, 0xfff, 0x20b, 0x260, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x37c, 0x2fd, + 0xfff, 0xfff, 0x2c8, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x31e, 0xfff, 0x335, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x135, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x35c, 0x4dd, 0x129, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x1ef, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x34e, 0xfff, 0xfff, 0xfff, 0xfff, 0x407, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x3ad, 0xfff, 0xfff, 0xfff, + 0x379, 0xfff, 0xfff, 0x1d0, 0x38d, 0xfff, 0xfff, 0x1e8, + 0x184, 0x3c1, 0x1c4, 0xfff, 0x1f9, 0xfff, 0xfff, 0x424, + 0xfff, 0xfff, 0xfff, 0xfff, 0x1d3, 0x0d4, 0xfff, 0x4e9, + 0xfff, 0xfff, 0xfff, 0x530, 0x107, 0xfff, 0x106, 0x04f, + 0xfff, 0xfff, 0x4c7, 0x503, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x15c, 0xfff, 0x23f, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x4f3, 0xfff, 0xfff, 0x3c7, + 0xfff, 0x278, 0xfff, 0xfff, 0x0a6, 0xfff, 0xfff, 0xfff, + 0x122, 0x1cf, 0xfff, 0x327, 0xfff, 0x2e5, 0xfff, 0x29d, + 0xfff, 0xfff, 0x3f1, 0xfff, 0xfff, 0x48d, 0xfff, 0xfff, + 0xfff, 0xfff, 0x054, 0xfff, 0xfff, 0xfff, 0xfff, 0x178, + 0x27e, 0x4e0, 0x352, 0x02f, 0x09c, 0xfff, 0x2a0, 0xfff, + 0xfff, 0x46a, 0x457, 0xfff, 0xfff, 0x501, 0xfff, 0x2ba, + 0xfff, 0xfff, 0xfff, 0x54e, 0x2e7, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x551, 0xfff, 0xfff, 0x1db, 0x2aa, 0xfff, + 0xfff, 0x4bc, 0xfff, 0xfff, 0x395, 0xfff, 0x0de, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x455, 0xfff, 0x17e, + 0xfff, 0x221, 0x4a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x388, 0xfff, 0xfff, 0xfff, 0x308, 0xfff, 0xfff, 0xfff, + 0x20e, 0x4b9, 0xfff, 0x273, 0x20c, 0x09e, 0xfff, 0x057, + 0xfff, 0xfff, 0xfff, 0xfff, 0x3f2, 0xfff, 0x1a8, 0x3a6, + 0x14c, 0xfff, 0xfff, 0x071, 0xfff, 0xfff, 0x53a, 0xfff, + 0xfff, 0xfff, 0xfff, 0x109, 0xfff, 0xfff, 0x399, 0xfff, + 0x061, 0x4f0, 0x39e, 0x244, 0xfff, 0x035, 0xfff, 0xfff, + 0x305, 0x47e, 0x297, 0xfff, 0xfff, 0x2b8, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1bc, 0xfff, 0x2fc, + 0xfff, 0xfff, 0x554, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b6, + 0xfff, 0xfff, 0xfff, 0x515, 0x397, 0xfff, 0xfff, 0x12f, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e5, + 0xfff, 0x4fc, 0xfff, 0xfff, 0x05e, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x0a8, 0x3af, 0x015, 0xfff, 0xfff, 0xfff, + 0xfff, 0x138, 0xfff, 0xfff, 0xfff, 0x540, 0xfff, 0xfff, + 0xfff, 0x027, 0x523, 0x2f0, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x16c, 0xfff, 0x27d, 0xfff, 0xfff, 0xfff, + 0xfff, 0x04c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4dc, + 0xfff, 0xfff, 0x059, 0x301, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x1a3, 0xfff, 0x15a, 0xfff, 0xfff, + 0x0a5, 0xfff, 0x435, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x051, 0xfff, 0xfff, 0x131, 0xfff, 0x4f4, 0xfff, + 0xfff, 0xfff, 0xfff, 0x441, 0xfff, 0x4fb, 0xfff, 0x03b, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ed, 0x274, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d3, 0x55e, 0x1b3, + 0xfff, 0x0bd, 0xfff, 0xfff, 0xfff, 0xfff, 0x225, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x4b7, 0xfff, 0xfff, 0x2ff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c3, 0xfff, + 0x383, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f6, + 0xfff, 0xfff, 0x1ee, 0xfff, 0x03d, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x26f, 0x1dc, 0xfff, 0x0db, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x0ce, 0xfff, 0xfff, 0x127, 0x03a, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x311, 0xfff, + 0xfff, 0x13d, 0x09d, 0x47b, 0x2a6, 0x50d, 0x510, 0x19a, + 0xfff, 0x354, 0x414, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x44c, 0x3b0, 0xfff, 0x23d, 0x429, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x4c0, 0x416, 0xfff, 0x05b, 0xfff, 0xfff, 0x137, 0xfff, + 0x25f, 0x49f, 0xfff, 0x279, 0x013, 0xfff, 0xfff, 0xfff, + 0x269, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d0, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x077, 0xfff, 0xfff, 0x3fb, + 0xfff, 0xfff, 0xfff, 0xfff, 0x271, 0x3a0, 0xfff, 0xfff, + 0x40f, 0xfff, 0xfff, 0x3de, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ab, 0x26a, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x489, 0xfff, 0xfff, + 0x252, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b7, 0x42f, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b7, + 0xfff, 0x2bb, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x0f7, 0x01d, 0xfff, 0x067, 0xfff, + 0xfff, 0xfff, 0xfff, 0x4e2, 0xfff, 0xfff, 0x4bb, 0xfff, + 0xfff, 0xfff, 0x17b, 0xfff, 0x0ee, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x36e, 0xfff, 0xfff, 0xfff, 0x533, 0xfff, + 0xfff, 0xfff, 0x4d4, 0x356, 0xfff, 0xfff, 0x375, 0xfff, + 0xfff, 0xfff, 0xfff, 0x4a4, 0x513, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4ff, 0xfff, 0x2af, + 0xfff, 0xfff, 0x026, 0xfff, 0x0ad, 0xfff, 0xfff, 0xfff, + 0xfff, 0x26e, 0xfff, 0xfff, 0xfff, 0xfff, 0x493, 0xfff, + 0x463, 0x4d2, 0x4be, 0xfff, 0xfff, 0xfff, 0xfff, 0x4f2, + 0x0b6, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x32d, 0x315, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x13a, 0x4a1, 0xfff, 0x27a, 0xfff, 0xfff, 0xfff, + 0x47a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x334, 0xfff, 0xfff, 0xfff, 0xfff, 0x54c, 0xfff, 0xfff, + 0xfff, 0x0c9, 0x007, 0xfff, 0xfff, 0x12e, 0xfff, 0x0ff, + 0xfff, 0xfff, 0x3f5, 0x509, 0xfff, 0xfff, 0xfff, 0xfff, + 0x1c3, 0x2ad, 0xfff, 0xfff, 0x47c, 0x261, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x152, 0xfff, 0xfff, 0xfff, 0x339, + 0xfff, 0x243, 0x1c0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x063, 0xfff, 0xfff, 0x254, 0xfff, 0xfff, 0x173, 0xfff, + 0x0c7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x362, 0x259, 0x485, 0x374, 0x0dc, 0x3ab, 0xfff, + 0x1c5, 0x534, 0x544, 0xfff, 0xfff, 0x508, 0xfff, 0x402, + 0x408, 0xfff, 0x0e7, 0xfff, 0xfff, 0x00a, 0x205, 0xfff, + 0xfff, 0x2b9, 0xfff, 0xfff, 0xfff, 0x465, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x23a, 0xfff, 0xfff, 0xfff, + 0xfff, 0x147, 0x19d, 0x115, 0x214, 0xfff, 0x090, 0x368, + 0xfff, 0x210, 0xfff, 0xfff, 0x280, 0x52a, 0x163, 0x148, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x326, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x2de, 0xfff, 0xfff, 0xfff, 0xfff, + 0x206, 0x2c1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x189, 0xfff, 0xfff, 0xfff, 0xfff, 0x367, 0xfff, 0x1a4, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x443, 0xfff, 0x27b, + 0xfff, 0xfff, 0x251, 0x549, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x188, 0x04b, 0xfff, 0xfff, 0xfff, 0x31f, + 0x4a6, 0xfff, 0x246, 0x1de, 0x156, 0xfff, 0xfff, 0xfff, + 0x3a9, 0xfff, 0xfff, 0xfff, 0x2fa, 0xfff, 0x128, 0x0d1, + 0x449, 0x255, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x258, 0xfff, 0xfff, 0xfff, + 0x532, 0xfff, 0xfff, 0xfff, 0x303, 0x517, 0xfff, 0xfff, + 0x2a9, 0x24a, 0xfff, 0xfff, 0x231, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x4b6, 0x516, 0xfff, 0xfff, 0x0e4, 0x0eb, + 0xfff, 0x4e4, 0xfff, 0x275, 0xfff, 0xfff, 0x031, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x025, 0x21a, 0xfff, 0x0cc, + 0x45f, 0x3d9, 0x289, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x23e, 0xfff, 0xfff, 0xfff, 0x438, 0x097, + 0x419, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x0a9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x37e, 0x0e0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x431, + 0x372, 0xfff, 0xfff, 0xfff, 0x1ba, 0x06e, 0xfff, 0x1b1, + 0xfff, 0xfff, 0x12a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x193, 0xfff, 0xfff, 0xfff, 0xfff, 0x10a, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x048, 0x1b4, + 0xfff, 0xfff, 0xfff, 0xfff, 0x295, 0x140, 0x108, 0xfff, + 0xfff, 0xfff, 0xfff, 0x16f, 0xfff, 0x0a4, 0x37a, 0xfff, + 0x29a, 0xfff, 0x284, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c6, + 0x2a2, 0x3a3, 0xfff, 0x201, 0xfff, 0xfff, 0xfff, 0x4bd, + 0x005, 0x54a, 0x3b5, 0x204, 0x2ee, 0x11d, 0x436, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x3ec, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x11f, 0x498, 0x21c, 0xfff, + 0xfff, 0xfff, 0x3d6, 0xfff, 0x4ab, 0xfff, 0x432, 0x2eb, + 0x542, 0x4fd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x4ce, 0xfff, 0xfff, 0x2fb, 0xfff, + 0xfff, 0x2e1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b9, 0x037, 0x0dd, + 0xfff, 0xfff, 0xfff, 0x2bf, 0x521, 0x496, 0x095, 0xfff, + 0xfff, 0x328, 0x070, 0x1bf, 0xfff, 0x393, 0xfff, 0xfff, + 0x102, 0xfff, 0xfff, 0x21b, 0xfff, 0x142, 0x263, 0x519, + 0xfff, 0x2a5, 0x177, 0xfff, 0x14d, 0x471, 0x4ae, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x1f6, 0xfff, 0x481, 0xfff, 0xfff, 0xfff, 0x151, 0xfff, + 0xfff, 0xfff, 0x085, 0x33f, 0xfff, 0xfff, 0xfff, 0x084, + 0xfff, 0xfff, 0xfff, 0x345, 0x3a2, 0xfff, 0xfff, 0x0a0, + 0x0da, 0x024, 0xfff, 0xfff, 0xfff, 0x1bd, 0xfff, 0x55c, + 0x467, 0x445, 0xfff, 0xfff, 0xfff, 0x052, 0xfff, 0xfff, + 0xfff, 0xfff, 0x51e, 0xfff, 0xfff, 0x39d, 0xfff, 0x35f, + 0xfff, 0x376, 0x3ee, 0xfff, 0xfff, 0xfff, 0xfff, 0x448, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x16a, + 0xfff, 0x036, 0x38f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x211, + 0xfff, 0xfff, 0xfff, 0x230, 0xfff, 0xfff, 0x3ba, 0xfff, + 0xfff, 0xfff, 0x3ce, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x229, 0xfff, 0x176, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x00b, 0xfff, 0x162, 0x018, 0xfff, + 0xfff, 0x233, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x400, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x12b, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x3f4, 0xfff, 0x0f0, 0xfff, 0x1ac, 0xfff, 0xfff, + 0x119, 0xfff, 0x2c0, 0xfff, 0xfff, 0xfff, 0x49b, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x23c, 0xfff, + 0x4b3, 0x010, 0x064, 0xfff, 0xfff, 0x4ba, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x3c2, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x006, 0x196, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x100, 0x191, 0xfff, + 0x1ea, 0x29f, 0xfff, 0xfff, 0xfff, 0x276, 0xfff, 0xfff, + 0x2b1, 0x3b9, 0xfff, 0x03c, 0xfff, 0xfff, 0xfff, 0x180, + 0xfff, 0x08f, 0xfff, 0xfff, 0x19e, 0x019, 0xfff, 0x0b0, + 0x0fd, 0x332, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x06b, 0x2e8, 0xfff, 0x446, 0xfff, 0xfff, 0x004, + 0x247, 0x197, 0xfff, 0x112, 0x169, 0x292, 0xfff, 0x302, + 0xfff, 0xfff, 0x33b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x287, 0x21f, 0xfff, 0x3ea, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e7, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x3a8, 0xfff, 0xfff, 0x2bc, 0xfff, + 0x484, 0x296, 0xfff, 0x1c9, 0x08c, 0x1e5, 0x48a, 0xfff, + 0x360, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x1ca, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x10d, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x066, 0x2ea, 0x28b, 0x25b, 0xfff, 0x072, + 0xfff, 0xfff, 0xfff, 0xfff, 0x2b6, 0xfff, 0xfff, 0x272, + 0xfff, 0xfff, 0x525, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x2ca, 0xfff, 0xfff, 0xfff, 0x299, 0xfff, 0xfff, 0xfff, + 0x558, 0x41a, 0xfff, 0x4f7, 0x557, 0xfff, 0x4a0, 0x344, + 0x12c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x125, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x40e, 0xfff, 0xfff, 0x502, 0xfff, 0x103, 0x3e6, 0xfff, + 0x527, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x45d, 0xfff, 0xfff, 0xfff, 0xfff, + 0x44e, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d2, 0x4c9, 0x35e, + 0x459, 0x2d9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x17d, + 0x0c4, 0xfff, 0xfff, 0xfff, 0x3ac, 0x390, 0x094, 0xfff, + 0x483, 0x0ab, 0xfff, 0x253, 0xfff, 0x391, 0xfff, 0xfff, + 0xfff, 0xfff, 0x123, 0x0ef, 0xfff, 0xfff, 0xfff, 0x330, + 0x38c, 0xfff, 0xfff, 0x2ae, 0xfff, 0xfff, 0xfff, 0x042, + 0x012, 0x06d, 0xfff, 0xfff, 0xfff, 0x32a, 0x3db, 0x364, + 0x2dc, 0xfff, 0x30f, 0x3d7, 0x4a5, 0x050, 0xfff, 0xfff, + 0x029, 0xfff, 0xfff, 0xfff, 0xfff, 0x1d1, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x480, 0xfff, + 0x4ed, 0x081, 0x0a1, 0xfff, 0xfff, 0xfff, 0x30e, 0x52f, + 0x257, 0xfff, 0xfff, 0x447, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x401, 0x3cc, 0xfff, 0xfff, 0x0fb, + 0x2c9, 0x42a, 0x314, 0x33e, 0x3bd, 0x318, 0xfff, 0x10e, + 0x2a1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x24c, + 0x506, 0xfff, 0x267, 0xfff, 0xfff, 0x219, 0xfff, 0x1eb, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x309, 0x3e2, 0x46c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x384, 0xfff, 0xfff, 0xfff, 0xfff, 0x50c, 0xfff, 0x24b, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x038, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x194, + 0x143, 0x3e3, 0xfff, 0xfff, 0xfff, 0x4c2, 0xfff, 0xfff, + 0x0e1, 0x25c, 0xfff, 0x237, 0xfff, 0x1fe, 0xfff, 0xfff, + 0xfff, 0x065, 0x2a4, 0xfff, 0x386, 0x55a, 0x11b, 0xfff, + 0xfff, 0x192, 0xfff, 0x183, 0x00e, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x4b2, 0x18e, 0xfff, 0xfff, 0xfff, + 0xfff, 0x486, 0x4ef, 0x0c6, 0x380, 0xfff, 0x4a8, 0xfff, + 0x0c5, 0xfff, 0xfff, 0xfff, 0xfff, 0x093, 0x1b8, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e6, + 0xfff, 0x0f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x28e, 0xfff, 0x53b, 0x420, 0x22a, 0x33a, 0xfff, 0x387, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2a3, 0xfff, 0xfff, + 0xfff, 0x428, 0x500, 0xfff, 0xfff, 0x120, 0x2c6, 0x290, + 0x2f5, 0x0e3, 0xfff, 0x0b7, 0xfff, 0x319, 0x474, 0xfff, + 0xfff, 0xfff, 0x529, 0x014, 0xfff, 0x41b, 0x40a, 0x18b, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d9, + 0xfff, 0x38a, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ce, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x3b1, 0xfff, 0xfff, 0x05d, + 0x2c4, 0xfff, 0xfff, 0x4af, 0xfff, 0x030, 0xfff, 0xfff, + 0x203, 0xfff, 0x277, 0x256, 0xfff, 0xfff, 0xfff, 0x4f9, + 0xfff, 0x2c7, 0xfff, 0x466, 0x016, 0x1cd, 0xfff, 0x167, + 0xfff, 0xfff, 0x0c8, 0xfff, 0x43d, 0xfff, 0xfff, 0x020, + 0xfff, 0xfff, 0x232, 0x1cb, 0x1e0, 0xfff, 0xfff, 0x347, + 0xfff, 0x478, 0xfff, 0x365, 0xfff, 0xfff, 0xfff, 0xfff, + 0x358, 0xfff, 0x10b, 0xfff, 0x35d, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x452, 0x22d, 0xfff, 0xfff, 0x47d, 0xfff, + 0x2f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x460, 0xfff, + 0xfff, 0xfff, 0x50b, 0xfff, 0xfff, 0xfff, 0x2ec, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x4b1, 0x422, 0xfff, 0xfff, + 0xfff, 0x2d4, 0xfff, 0x239, 0xfff, 0xfff, 0xfff, 0x439, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x491, 0x075, 0xfff, 0xfff, 0xfff, 0x06c, 0xfff, + 0xfff, 0x0f9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x139, 0xfff, 0x4f6, 0xfff, 0xfff, 0x409, 0xfff, + 0xfff, 0x15b, 0xfff, 0xfff, 0x348, 0xfff, 0xfff, 0xfff, + 0xfff, 0x4a2, 0x49d, 0xfff, 0x033, 0x175, 0xfff, 0x039, + 0xfff, 0x312, 0x40c, 0xfff, 0xfff, 0x325, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x4aa, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0x165, 0x3bc, 0x48c, 0x310, 0x096, + 0xfff, 0xfff, 0x250, 0x1a2, 0xfff, 0xfff, 0xfff, 0xfff, + 0x20d, 0x2ac, 0xfff, 0xfff, 0x39b, 0xfff, 0x377, 0xfff, + 0x512, 0x495, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x357, 0x4ea, 0xfff, 0xfff, + 0xfff, 0xfff, 0x198, 0xfff, 0xfff, 0xfff, 0x434, 0x04a, + 0xfff, 0xfff, 0xfff, 0xfff, 0x062, 0xfff, 0x1d6, 0x1c8, + 0xfff, 0x1f3, 0x281, 0xfff, 0x462, 0xfff, 0xfff, 0xfff, + 0x4b0, 0xfff, 0x207, 0xfff, 0xfff, 0xfff, 0xfff, 0x3dd, + 0xfff, 0xfff, 0x55d, 0xfff, 0x552, 0x494, 0x1af, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x227, 0xfff, 0xfff, 0x069, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x43e, + 0x0b5, 0xfff, 0x524, 0x2d2, 0xfff, 0xfff, 0xfff, 0x28f, + 0xfff, 0x01b, 0x50e, 0xfff, 0xfff, 0x1bb, 0xfff, 0xfff, + 0x41d, 0xfff, 0x32e, 0x48e, 0xfff, 0x1f7, 0x224, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x394, 0xfff, 0xfff, 0xfff, + 0xfff, 0x52c, 0xfff, 0xfff, 0xfff, 0x392, 0xfff, 0x1e7, + 0xfff, 0xfff, 0x3f9, 0x3a7, 0xfff, 0x51f, 0xfff, 0x0bb, + 0x118, 0x3ca, 0xfff, 0x1dd, 0xfff, 0x48b, 0xfff, 0xfff, + 0xfff, 0xfff, 0x50f, 0xfff, 0x0d6, 0xfff, 0x1fa, 0xfff, + 0x11e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d7, 0xfff, 0x078, + 0x008, 0xfff, 0x25d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x032, 0x33c, 0xfff, 0x4d9, 0x160, 0xfff, 0xfff, 0x300, + 0x0b1, 0xfff, 0x322, 0xfff, 0x4ec, 0xfff, 0xfff, 0x200, + 0x00c, 0x369, 0x473, 0xfff, 0xfff, 0x32c, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x53e, 0x3d4, 0x417, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x34b, 0x001, 0x39a, 0x02c, 0xfff, 0xfff, 0x2ce, 0x00f, + 0xfff, 0x0ba, 0xfff, 0xfff, 0xfff, 0xfff, 0x060, 0xfff, + 0x406, 0xfff, 0xfff, 0xfff, 0x4ee, 0x4ac, 0xfff, 0x43f, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x29b, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x216, + 0x190, 0xfff, 0x396, 0x464, 0xfff, 0xfff, 0x323, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e9, 0xfff, 0x26d, + 0x2cd, 0x040, 0xfff, 0xfff, 0xfff, 0xfff, 0x38b, 0x3c0, + 0xfff, 0xfff, 0xfff, 0x1f2, 0xfff, 0x0ea, 0xfff, 0xfff, + 0x472, 0xfff, 0x1fb, 0xfff, 0xfff, 0x0af, 0x27f, 0xfff, + 0xfff, 0xfff, 0x479, 0x023, 0xfff, 0x0d8, 0x3b3, 0xfff, + 0xfff, 0xfff, 0x121, 0xfff, 0xfff, 0x3bf, 0xfff, 0xfff, + 0x16b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x45a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0x0be, 0xfff, 0xfff, 0xfff, 0x111, 0xfff, 0x220, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0x09b, 0x218, 0xfff, 0x022, 0x202, 0xfff, + 0x4c8, 0xfff, 0x0ed, 0xfff, 0xfff, 0x182, 0xfff, 0xfff, + 0xfff, 0x17f, 0x213, 0xfff, 0x321, 0x36a, 0xfff, 0x086, + 0xfff, 0xfff, 0xfff, 0x43b, 0x088, 0xfff, 0xfff, 0xfff, + 0xfff, 0x26c, 0xfff, 0x2f8, 0x3b4, 0xfff, 0xfff, 0xfff, + 0x132, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x333, 0x444, + 0x0c1, 0x4d8, 0x46d, 0x264, 0xfff, 0xfff, 0xfff, 0xfff, + 0x426, 0xfff, 0xfff, 0xfff, 0xfff, 0x2fe, 0xfff, 0xfff, + 0xfff, 0xfff, 0x011, 0xfff, 0x05f, 0xfff, 0xfff, 0xfff, + 0xfff, 0x10c, 0x101, 0xfff, 0xfff, 0xfff, 0xfff, 0x110, + 0xfff, 0x044, 0x304, 0x361, 0x404, 0xfff, 0x51b, 0x099, + 0xfff, 0x440, 0xfff, 0xfff, 0xfff, 0x222, 0xfff, 0xfff, + 0xfff, 0xfff, 0x1b5, 0xfff, 0x136, 0x430, 0xfff, 0x1da, + 0xfff, 0xfff, 0xfff, 0x043, 0xfff, 0x17c, 0xfff, 0xfff, + 0xfff, 0x01c, 0xfff, 0xfff, 0xfff, 0x425, 0x236, 0xfff, + 0x317, 0xfff, 0xfff, 0x437, 0x3fc, 0xfff, 0x1f1, 0xfff, + 0x324, 0xfff, 0xfff, 0x0ca, 0x306, 0xfff, 0x548, 0xfff, + 0x46e, 0xfff, 0xfff, 0xfff, 0x4b8, 0x1c2, 0x286, 0xfff, + 0xfff, 0x087, 0x18a, 0x19f, 0xfff, 0xfff, 0xfff, 0xfff, + 0x18c, 0xfff, 0x215, 0xfff, 0xfff, 0xfff, 0xfff, 0x283, + 0xfff, 0xfff, 0xfff, 0x126, 0xfff, 0xfff, 0x370, 0xfff, + 0x53f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x31c, 0xfff, + 0x4d1, 0xfff, 0xfff, 0xfff, 0x021, 0xfff, 0x157, 0xfff, + 0xfff, 0x028, 0x16e, 0xfff, 0x421, 0xfff, 0x1c6, 0xfff, + 0xfff, 0x511, 0xfff, 0xfff, 0x39c, 0x46f, 0x1b2, 0xfff, + 0xfff, 0x316, 0xfff, 0xfff, 0x009, 0xfff, 0xfff, 0x195, + 0xfff, 0x240, 0x546, 0xfff, 0xfff, 0x520, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x454, 0xfff, 0xfff, 0xfff, + 0x3f3, 0xfff, 0xfff, 0x187, 0xfff, 0x4a9, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x51c, 0x453, 0x1e6, 0xfff, + 0xfff, 0xfff, 0x1b0, 0xfff, 0x477, 0xfff, 0xfff, 0xfff, + 0x4fe, 0xfff, 0x32f, 0xfff, 0xfff, 0x15e, 0x1d4, 0xfff, + 0x0e5, 0xfff, 0xfff, 0xfff, 0x242, 0x14b, 0x046, 0xfff, + 0x3f6, 0x3bb, 0x3e4, 0xfff, 0xfff, 0x2e3, 0xfff, 0x245, + 0xfff, 0x149, 0xfff, 0xfff, 0xfff, 0x2db, 0xfff, 0xfff, + 0x181, 0xfff, 0x089, 0x2c5, 0xfff, 0x1f5, 0xfff, 0x2d6, + 0x507, 0xfff, 0x42d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0x080, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, + 0xfff, 0xfff, 0xfff, 0xfff, 0x3c3, 0x320, 0xfff, 0x1e1, + 0xfff, 0x0f5, 0x13b, 0xfff, 0xfff, 0xfff, 0x003, 0x4da, + 0xfff, 0xfff, 0xfff, 0x42c, 0xfff, 0xfff, 0x0cb, 0xfff, + 0x536, 0x2c3, 0xfff, 0xfff, 0xfff, 0xfff, 0x199, 0xfff, + 0xfff, 0x0c0, 0xfff, 0x01e, 0x497, 0xfff, 0xfff, 0x3e5, + 0xfff, 0xfff, 0xfff, 0x0cf, 0xfff, 0x2bd, 0xfff, 0x223, + 0xfff, 0x3ff, 0xfff, 0x058, 0x174, 0x3ef, 0xfff, 0x002 +}; + +static unsigned short err_pos(unsigned short din) +{ + BUG_ON(din > 4096); + return err_pos_lut[din]; +} +static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) +{ + if ((chk_syndrome_list[0] | chk_syndrome_list[1] | + chk_syndrome_list[2] | chk_syndrome_list[3] | + chk_syndrome_list[4] | chk_syndrome_list[5] | + chk_syndrome_list[6] | chk_syndrome_list[7]) != 0x0) { + return -EINVAL; + } else { + err_info[0] = 0x0; + return 0; + } +} +static int chk_1_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) +{ + unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + tmp0 = gf4096_mul(chk_syndrome_list[1], gf4096_inv(chk_syndrome_list[0])); + tmp1 = gf4096_mul(chk_syndrome_list[2], gf4096_inv(chk_syndrome_list[1])); + tmp2 = gf4096_mul(chk_syndrome_list[3], gf4096_inv(chk_syndrome_list[2])); + tmp3 = gf4096_mul(chk_syndrome_list[4], gf4096_inv(chk_syndrome_list[3])); + tmp4 = gf4096_mul(chk_syndrome_list[5], gf4096_inv(chk_syndrome_list[4])); + tmp5 = gf4096_mul(chk_syndrome_list[6], gf4096_inv(chk_syndrome_list[5])); + tmp6 = gf4096_mul(chk_syndrome_list[7], gf4096_inv(chk_syndrome_list[6])); + if ((tmp0 == tmp1) & (tmp1 == tmp2) & (tmp2 == tmp3) & (tmp3 == tmp4) & (tmp4 == tmp5) & (tmp5 == tmp6)) { + err_info[0] = 0x1; // encode 1-symbol error as 0x1 + err_info[1] = err_pos(tmp0); + err_info[1] = (unsigned short)(0x55e - err_info[1]); + err_info[5] = chk_syndrome_list[0]; + return 0; + } else + return -EINVAL; +} +static int chk_2_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) +{ + unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + unsigned short coefs[4]; + unsigned short err_pats[4]; + int found_num_root = 0; + unsigned short bit2_root0, bit2_root1; + unsigned short bit2_root0_inv, bit2_root1_inv; + unsigned short err_loc_eqn, test_root; + unsigned short bit2_loc0, bit2_loc1; + unsigned short bit2_pat0, bit2_pat1; + + find_2x2_soln(chk_syndrome_list[1], + chk_syndrome_list[0], + chk_syndrome_list[2], chk_syndrome_list[1], chk_syndrome_list[2], chk_syndrome_list[3], coefs); + for (test_root = 0x1; test_root < 0xfff; test_root++) { + err_loc_eqn = + gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) ^ 0x1; + if (err_loc_eqn == 0x0) { + if (found_num_root == 0) { + bit2_root0 = test_root; + found_num_root = 1; + } else if (found_num_root == 1) { + bit2_root1 = test_root; + found_num_root = 2; + break; + } + } + } + if (found_num_root != 2) + return -EINVAL; + else { + bit2_root0_inv = gf4096_inv(bit2_root0); + bit2_root1_inv = gf4096_inv(bit2_root1); + find_2bit_err_pats(chk_syndrome_list[0], + chk_syndrome_list[1], bit2_root0_inv, bit2_root1_inv, err_pats); + bit2_pat0 = err_pats[0]; + bit2_pat1 = err_pats[1]; + //for(x+1) + tmp0 = gf4096_mul(gf4096_mul(bit2_root0_inv, bit2_root0_inv), gf4096_mul(bit2_root0_inv, bit2_root0_inv)); //rinv0^4 + tmp1 = gf4096_mul(bit2_root0_inv, tmp0); //rinv0^5 + tmp2 = gf4096_mul(bit2_root0_inv, tmp1); //rinv0^6 + tmp3 = gf4096_mul(bit2_root0_inv, tmp2); //rinv0^7 + tmp4 = gf4096_mul(gf4096_mul(bit2_root1_inv, bit2_root1_inv), gf4096_mul(bit2_root1_inv, bit2_root1_inv)); //rinv1^4 + tmp5 = gf4096_mul(bit2_root1_inv, tmp4); //rinv1^5 + tmp6 = gf4096_mul(bit2_root1_inv, tmp5); //rinv1^6 + tmp7 = gf4096_mul(bit2_root1_inv, tmp6); //rinv1^7 + //check if only 2-bit error + if ((chk_syndrome_list[4] == + (gf4096_mul(bit2_pat0, tmp0) ^ + gf4096_mul(bit2_pat1, + tmp4))) & (chk_syndrome_list[5] == + (gf4096_mul(bit2_pat0, tmp1) ^ + gf4096_mul(bit2_pat1, + tmp5))) & + (chk_syndrome_list[6] == + (gf4096_mul(bit2_pat0, tmp2) ^ + gf4096_mul(bit2_pat1, + tmp6))) & (chk_syndrome_list[7] == + (gf4096_mul(bit2_pat0, tmp3) ^ gf4096_mul(bit2_pat1, tmp7)))) { + if ((err_pos(bit2_root0_inv) == 0xfff) | (err_pos(bit2_root1_inv) == 0xfff)) { + return -EINVAL; + } else { + bit2_loc0 = 0x55e - err_pos(bit2_root0_inv); + bit2_loc1 = 0x55e - err_pos(bit2_root1_inv); + err_info[0] = 0x2; // encode 2-symbol error as 0x2 + err_info[1] = bit2_loc0; + err_info[2] = bit2_loc1; + err_info[5] = bit2_pat0; + err_info[6] = bit2_pat1; + return 0; + } + } else + return -EINVAL; + } +} +static int chk_3_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) +{ + unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + unsigned short coefs[4]; + unsigned short err_pats[4]; + int found_num_root = 0; + unsigned short bit3_root0, bit3_root1, bit3_root2; + unsigned short bit3_root0_inv, bit3_root1_inv, bit3_root2_inv; + unsigned short err_loc_eqn, test_root; + + find_3bit_err_coefs(chk_syndrome_list[0], chk_syndrome_list[1], + chk_syndrome_list[2], chk_syndrome_list[3], + chk_syndrome_list[4], chk_syndrome_list[5], coefs); + + for (test_root = 0x1; test_root < 0xfff; test_root++) { + err_loc_eqn = gf4096_mul(coefs[2], + gf4096_mul(gf4096_mul(test_root, test_root), + test_root)) ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) + ^ gf4096_mul(coefs[0], test_root) ^ 0x1; + + if (err_loc_eqn == 0x0) { + if (found_num_root == 0) { + bit3_root0 = test_root; + found_num_root = 1; + } else if (found_num_root == 1) { + bit3_root1 = test_root; + found_num_root = 2; + } else if (found_num_root == 2) { + bit3_root2 = test_root; + found_num_root = 3; + break; + } + } + } + if (found_num_root != 3) + return -EINVAL; + else { + bit3_root0_inv = gf4096_inv(bit3_root0); + bit3_root1_inv = gf4096_inv(bit3_root1); + bit3_root2_inv = gf4096_inv(bit3_root2); + + find_3bit_err_pats(chk_syndrome_list[0], chk_syndrome_list[1], + chk_syndrome_list[2], bit3_root0_inv, + bit3_root1_inv, bit3_root2_inv, err_pats); + + //check if only 3-bit error + tmp0 = gf4096_mul(bit3_root0_inv, bit3_root0_inv); + tmp0 = gf4096_mul(tmp0, tmp0); + tmp0 = gf4096_mul(tmp0, bit3_root0_inv); + tmp0 = gf4096_mul(tmp0, bit3_root0_inv); //rinv0^6 + tmp1 = gf4096_mul(tmp0, bit3_root0_inv); //rinv0^7 + tmp2 = gf4096_mul(bit3_root1_inv, bit3_root1_inv); + tmp2 = gf4096_mul(tmp2, tmp2); + tmp2 = gf4096_mul(tmp2, bit3_root1_inv); + tmp2 = gf4096_mul(tmp2, bit3_root1_inv); //rinv1^6 + tmp3 = gf4096_mul(tmp2, bit3_root1_inv); //rinv1^7 + tmp4 = gf4096_mul(bit3_root2_inv, bit3_root2_inv); + tmp4 = gf4096_mul(tmp4, tmp4); + tmp4 = gf4096_mul(tmp4, bit3_root2_inv); + tmp4 = gf4096_mul(tmp4, bit3_root2_inv); //rinv2^6 + tmp5 = gf4096_mul(tmp4, bit3_root2_inv); //rinv2^7 + + //check if only 3 errors + if ((chk_syndrome_list[6] == (gf4096_mul(err_pats[0], tmp0) ^ + gf4096_mul(err_pats[1], tmp2) ^ + gf4096_mul(err_pats[2], tmp4))) & + (chk_syndrome_list[7] == (gf4096_mul(err_pats[0], tmp1) ^ + gf4096_mul(err_pats[1], tmp3) ^ gf4096_mul(err_pats[2], tmp5)))) { + if ((err_pos(bit3_root0_inv) == 0xfff) | + (err_pos(bit3_root1_inv) == 0xfff) | (err_pos(bit3_root2_inv) == 0xfff)) { + return -EINVAL; + } else { + err_info[0] = 0x3; + err_info[1] = (0x55e - err_pos(bit3_root0_inv)); + err_info[2] = (0x55e - err_pos(bit3_root1_inv)); + err_info[3] = (0x55e - err_pos(bit3_root2_inv)); + err_info[5] = err_pats[0]; + err_info[6] = err_pats[1]; + err_info[7] = err_pats[2]; + return 0; + } + } else + return -EINVAL; + } +} +static int chk_4_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) +{ + unsigned short coefs[4]; + unsigned short err_pats[4]; + int found_num_root = 0; + unsigned short bit4_root0, bit4_root1, bit4_root2, bit4_root3; + unsigned short bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv; + unsigned short err_loc_eqn, test_root; + + find_4bit_err_coefs(chk_syndrome_list[0], + chk_syndrome_list[1], + chk_syndrome_list[2], + chk_syndrome_list[3], + chk_syndrome_list[4], + chk_syndrome_list[5], chk_syndrome_list[6], chk_syndrome_list[7], coefs); + + for (test_root = 0x1; test_root < 0xfff; test_root++) { + err_loc_eqn = + gf4096_mul(coefs[3], + gf4096_mul(gf4096_mul + (gf4096_mul(test_root, test_root), + test_root), + test_root)) ^ gf4096_mul(coefs[2], + gf4096_mul + (gf4096_mul(test_root, test_root), test_root)) + ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) + ^ 0x1; + if (err_loc_eqn == 0x0) { + if (found_num_root == 0) { + bit4_root0 = test_root; + found_num_root = 1; + } else if (found_num_root == 1) { + bit4_root1 = test_root; + found_num_root = 2; + } else if (found_num_root == 2) { + bit4_root2 = test_root; + found_num_root = 3; + } else { + found_num_root = 4; + bit4_root3 = test_root; + break; + } + } + } + if (found_num_root != 4) { + return -EINVAL; + } else { + bit4_root0_inv = gf4096_inv(bit4_root0); + bit4_root1_inv = gf4096_inv(bit4_root1); + bit4_root2_inv = gf4096_inv(bit4_root2); + bit4_root3_inv = gf4096_inv(bit4_root3); + find_4bit_err_pats(chk_syndrome_list[0], + chk_syndrome_list[1], + chk_syndrome_list[2], + chk_syndrome_list[3], + bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv, err_pats); + err_info[0] = 0x4; + err_info[1] = (0x55e - err_pos(bit4_root0_inv)); + err_info[2] = (0x55e - err_pos(bit4_root1_inv)); + err_info[3] = (0x55e - err_pos(bit4_root2_inv)); + err_info[4] = (0x55e - err_pos(bit4_root3_inv)); + err_info[5] = err_pats[0]; + err_info[6] = err_pats[1]; + err_info[7] = err_pats[2]; + err_info[8] = err_pats[3]; + return 0; + } +} + +void correct_12bit_symbol(unsigned char *buf, unsigned short sym, + unsigned short val) +{ + if (unlikely(sym > 1366)) { + printk(KERN_ERR "Error: symbol %d out of range; cannot correct\n", sym); + } else if (sym == 0) { + buf[0] ^= val; + } else if (sym & 1) { + buf[1+(3*(sym-1))/2] ^= (val >> 4); + buf[2+(3*(sym-1))/2] ^= ((val & 0xf) << 4); + } else { + buf[2+(3*(sym-2))/2] ^= (val >> 8); + buf[3+(3*(sym-2))/2] ^= (val & 0xff); + } +} + +static int debugecc = 0; +module_param(debugecc, int, 0644); + +int cafe_correct_ecc(unsigned char *buf, + unsigned short *chk_syndrome_list) +{ + unsigned short err_info[9]; + int i; + + if (debugecc) { + printk(KERN_WARNING "cafe_correct_ecc invoked. Syndromes %x %x %x %x %x %x %x %x\n", + chk_syndrome_list[0], chk_syndrome_list[1], + chk_syndrome_list[2], chk_syndrome_list[3], + chk_syndrome_list[4], chk_syndrome_list[5], + chk_syndrome_list[6], chk_syndrome_list[7]); + for (i=0; i < 2048; i+=16) { + printk(KERN_WARNING "D %04x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + i, + buf[i], buf[i+1], buf[i+2], buf[i+3], + buf[i+4], buf[i+5], buf[i+6], buf[i+7], + buf[i+8], buf[i+9], buf[i+10], buf[i+11], + buf[i+12], buf[i+13], buf[i+14], buf[i+15]); + } + for ( ; i < 2112; i+=16) { + printk(KERN_WARNING "O %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + i - 2048, + buf[i], buf[i+1], buf[i+2], buf[i+3], + buf[i+4], buf[i+5], buf[i+6], buf[i+7], + buf[i+8], buf[i+9], buf[i+10], buf[i+11], + buf[i+12], buf[i+13], buf[i+14], buf[i+15]); + } + } + + + + if (chk_no_err_only(chk_syndrome_list, err_info) && + chk_1_err_only(chk_syndrome_list, err_info) && + chk_2_err_only(chk_syndrome_list, err_info) && + chk_3_err_only(chk_syndrome_list, err_info) && + chk_4_err_only(chk_syndrome_list, err_info)) { + return -EIO; + } + + for (i=0; i < err_info[0]; i++) { + if (debugecc) + printk(KERN_WARNING "Correct symbol %d with 0x%03x\n", + err_info[1+i], err_info[5+i]); + + correct_12bit_symbol(buf, err_info[1+i], err_info[5+i]); + } + + return err_info[0]; +} + diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 94924d52a9b..8296305c829 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -11,7 +11,7 @@ * published by the Free Software Foundation. * * Overview: - * This is a device driver for the NAND flash controller found on + * This is a device driver for the NAND flash controller found on * the AMD CS5535/CS5536 companion chipsets for the Geode processor. * */ @@ -303,7 +303,7 @@ static int __init cs553x_init(void) err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF); } - /* Register all devices together here. This means we can easily hack it to + /* Register all devices together here. This means we can easily hack it to do mtdconcat etc. if we want to. */ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { if (cs553x_mtd[i]) { diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 6107f532855..12608c13cce 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1635,13 +1635,12 @@ static int __init doc_probe(unsigned long physadr) len = sizeof(struct mtd_info) + sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); - mtd = kmalloc(len, GFP_KERNEL); + mtd = kzalloc(len, GFP_KERNEL); if (!mtd) { printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); ret = -ENOMEM; goto fail; } - memset(mtd, 0, len); nand = (struct nand_chip *) (mtd + 1); doc = (struct doc_priv *) (nand + 1); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 41bfcae1fbf..dfe56e03e48 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -362,7 +362,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) * access */ ofs += mtd->oobsize; - chip->ops.len = 2; + chip->ops.len = chip->ops.ooblen = 2; chip->ops.datbuf = NULL; chip->ops.oobbuf = buf; chip->ops.ooboffs = chip->badblockpos & ~0x01; @@ -755,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_swecc - {REPLACABLE] software ecc based page read function + * nand_read_page_swecc - [REPLACABLE] software ecc based page read function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -795,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function + * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -839,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -897,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, * @chip: nand chip structure * @oob: oob destination address * @ops: oob ops structure + * @len: size of oob to transfer */ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, - struct mtd_oob_ops *ops) + struct mtd_oob_ops *ops, size_t len) { - size_t len = ops->ooblen; - switch(ops->mode) { case MTD_OOB_PLACE: @@ -960,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, int sndcmd = 1; int ret = 0; uint32_t readlen = ops->len; + uint32_t oobreadlen = ops->ooblen; uint8_t *bufpoi, *oob, *buf; stats = mtd->ecc_stats; @@ -971,7 +971,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; col = (int)(from & (mtd->writesize - 1)); - chip->oob_poi = chip->buffers->oobrbuf; buf = ops->datbuf; oob = ops->oobbuf; @@ -1007,10 +1006,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (unlikely(oob)) { /* Raw mode does data:oob:data:oob */ - if (ops->mode != MTD_OOB_RAW) - oob = nand_transfer_oob(chip, oob, ops); - else - buf = nand_transfer_oob(chip, buf, ops); + if (ops->mode != MTD_OOB_RAW) { + int toread = min(oobreadlen, + chip->ecc.layout->oobavail); + if (toread) { + oob = nand_transfer_oob(chip, + oob, ops, toread); + oobreadlen -= toread; + } + } else + buf = nand_transfer_oob(chip, + buf, ops, mtd->oobsize); } if (!(chip->options & NAND_NO_READRDY)) { @@ -1057,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } ops->retlen = ops->len - (size_t) readlen; + if (oob) + ops->oobretlen = ops->ooblen - oobreadlen; if (ret) return ret; @@ -1257,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, int page, realpage, chipnr, sndcmd = 1; struct nand_chip *chip = mtd->priv; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; - int readlen = ops->len; + int readlen = ops->ooblen; + int len; uint8_t *buf = ops->oobbuf; DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", (unsigned long long)from, readlen); + if (ops->mode == MTD_OOB_RAW) + len = mtd->oobsize; + else + len = chip->ecc.layout->oobavail; + chipnr = (int)(from >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -1270,11 +1284,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; - chip->oob_poi = chip->buffers->oobrbuf; - while(1) { sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); - buf = nand_transfer_oob(chip, buf, ops); + + len = min(len, readlen); + buf = nand_transfer_oob(chip, buf, ops, len); if (!(chip->options & NAND_NO_READRDY)) { /* @@ -1289,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } - readlen -= ops->ooblen; + readlen -= len; if (!readlen) break; @@ -1311,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, sndcmd = 1; } - ops->retlen = ops->len; + ops->oobretlen = ops->ooblen; return 0; } @@ -1332,7 +1346,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ops->retlen = 0; /* Do not allow reads past end of device */ - if ((from + ops->len) > mtd->size) { + if (ops->datbuf && (from + ops->len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt read beyond end of device\n"); return -EINVAL; @@ -1375,7 +1389,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_swecc - {REPLACABLE] software ecc based page write function + * nand_write_page_swecc - [REPLACABLE] software ecc based page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1401,7 +1415,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function + * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1429,7 +1443,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write + * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1577,7 +1591,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, return NULL; } -#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 +#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0 /** * nand_do_write_ops - [Internal] NAND write with ECC @@ -1590,15 +1604,16 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - int chipnr, realpage, page, blockmask; + int chipnr, realpage, page, blockmask, column; struct nand_chip *chip = mtd->priv; uint32_t writelen = ops->len; uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; - int bytes = mtd->writesize; - int ret; + int ret, subpage; ops->retlen = 0; + if (!writelen) + return 0; /* reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { @@ -1607,8 +1622,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, return -EINVAL; } - if (!writelen) - return 0; + column = to & (mtd->writesize - 1); + subpage = column || (writelen & (mtd->writesize - 1)); + + if (subpage && oob) + return -EINVAL; chipnr = (int)(to >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -1626,15 +1644,29 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - chip->oob_poi = chip->buffers->oobwbuf; + /* If we're not given explicit OOB data, let it be 0xFF */ + if (likely(!oob)) + memset(chip->oob_poi, 0xff, mtd->oobsize); while(1) { + int bytes = mtd->writesize; int cached = writelen > bytes && page != blockmask; + uint8_t *wbuf = buf; + + /* Partial page write ? */ + if (unlikely(column || writelen < (mtd->writesize - 1))) { + cached = 0; + bytes = min_t(int, bytes - column, (int) writelen); + chip->pagebuf = -1; + memset(chip->buffers->databuf, 0xff, mtd->writesize); + memcpy(&chip->buffers->databuf[column], buf, bytes); + wbuf = chip->buffers->databuf; + } if (unlikely(oob)) oob = nand_fill_oob(chip, oob, ops); - ret = chip->write_page(mtd, chip, buf, page, cached, + ret = chip->write_page(mtd, chip, wbuf, page, cached, (ops->mode == MTD_OOB_RAW)); if (ret) break; @@ -1643,6 +1675,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (!writelen) break; + column = 0; buf += bytes; realpage++; @@ -1655,10 +1688,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, } } - if (unlikely(oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - ops->retlen = ops->len - writelen; + if (unlikely(oob)) + ops->oobretlen = ops->ooblen; return ret; } @@ -1714,10 +1746,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct nand_chip *chip = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", - (unsigned int)to, (int)ops->len); + (unsigned int)to, (int)ops->ooblen); /* Do not allow write past end of page */ - if ((ops->ooboffs + ops->len) > mtd->oobsize) { + if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) { DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Attempt to write past end of page\n"); return -EINVAL; @@ -1745,7 +1777,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - chip->oob_poi = chip->buffers->oobwbuf; memset(chip->oob_poi, 0xff, mtd->oobsize); nand_fill_oob(chip, ops->oobbuf, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); @@ -1754,7 +1785,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (status) return status; - ops->retlen = ops->len; + ops->oobretlen = ops->ooblen; return 0; } @@ -1774,7 +1805,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ops->retlen = 0; /* Do not allow writes past end of device */ - if ((to + ops->len) > mtd->size) { + if (ops->datbuf && (to + ops->len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " "Attempt read beyond end of device\n"); return -EINVAL; @@ -2188,8 +2219,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Newer devices have all the information in additional id bytes */ if (!type->pagesize) { int extid; - /* The 3rd id byte contains non relevant data ATM */ - extid = chip->read_byte(mtd); + /* The 3rd id byte holds MLC / multichip data */ + chip->cellinfo = chip->read_byte(mtd); /* The 4th id byte is the important one */ extid = chip->read_byte(mtd); /* Calc pagesize */ @@ -2349,8 +2380,8 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->buffers) return -ENOMEM; - /* Preset the internal oob write buffer */ - memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize); + /* Set the internal oob buffer location, just after the page data */ + chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* * If no default placement scheme is given, select an appropriate one @@ -2469,6 +2500,24 @@ int nand_scan_tail(struct mtd_info *mtd) } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; + /* + * Allow subpage writes up to ecc.steps. Not possible for MLC + * FLASH. + */ + if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && + !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { + switch(chip->ecc.steps) { + case 2: + mtd->subpage_sft = 1; + break; + case 4: + case 8: + mtd->subpage_sft = 2; + break; + } + } + chip->subpagesize = mtd->writesize >> mtd->subpage_sft; + /* Initialize state */ chip->state = FL_READY; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 9402653eb09..5e121ceaa59 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -333,7 +333,6 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, struct mtd_oob_ops ops; int j, ret; - ops.len = mtd->oobsize; ops.ooblen = mtd->oobsize; ops.oobbuf = buf; ops.ooboffs = 0; @@ -676,10 +675,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, "bad block table\n"); } /* Read oob data */ - ops.len = (len >> this->page_shift) * mtd->oobsize; + ops.ooblen = (len >> this->page_shift) * mtd->oobsize; ops.oobbuf = &buf[len]; res = mtd->read_oob(mtd, to + mtd->writesize, &ops); - if (res < 0 || ops.retlen != ops.len) + if (res < 0 || ops.oobretlen != ops.ooblen) goto outerr; /* Calc the byte offset in the buffer */ @@ -961,14 +960,12 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct nand_bbt_descr *md = this->bbt_md; len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate memory (2bit per block) */ - this->bbt = kmalloc(len, GFP_KERNEL); + /* Allocate memory (2bit per block) and clear the memory bad block table */ + this->bbt = kzalloc(len, GFP_KERNEL); if (!this->bbt) { printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); return -ENOMEM; } - /* Clear the memory bad block table */ - memset(this->bbt, 0x00, len); /* If no primary table decriptor is given, scan the device * to build a memory based bad block table diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index dd438ca47d9..fde593e5e63 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -112,7 +112,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ /* Calculate final ECC code */ -#ifdef CONFIG_NAND_ECC_SMC +#ifdef CONFIG_MTD_NAND_ECC_SMC ecc_code[0] = ~tmp2; ecc_code[1] = ~tmp1; #else @@ -148,7 +148,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, { uint8_t s0, s1, s2; -#ifdef CONFIG_NAND_ECC_SMC +#ifdef CONFIG_MTD_NAND_ECC_SMC s0 = calc_ecc[0] ^ read_ecc[0]; s1 = calc_ecc[1] ^ read_ecc[1]; s2 = calc_ecc[2] ^ read_ecc[2]; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 545ff252d81..c3bca9590ad 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -37,10 +37,6 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <linux/delay.h> -#ifdef CONFIG_NS_ABS_POS -#include <asm/io.h> -#endif - /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -164,7 +160,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); /* After a command is input, the simulator goes to one of the following states */ #define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ #define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ -#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ +#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ #define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */ #define STATE_CMD_READOOB 0x00000005 /* read OOB area */ #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ @@ -231,6 +227,14 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); #define NS_MAX_PREVSTATES 1 /* + * A union to represent flash memory contents and flash buffer. + */ +union ns_mem { + u_char *byte; /* for byte access */ + uint16_t *word; /* for 16-bit word access */ +}; + +/* * The structure which describes all the internal simulator data. */ struct nandsim { @@ -247,17 +251,11 @@ struct nandsim { uint16_t npstates; /* number of previous states saved */ uint16_t stateidx; /* current state index */ - /* The simulated NAND flash image */ - union flash_media { - u_char *byte; - uint16_t *word; - } mem; + /* The simulated NAND flash pages array */ + union ns_mem *pages; /* Internal buffer of page + OOB size bytes */ - union internal_buffer { - u_char *byte; /* for byte access */ - uint16_t *word; /* for 16-bit word access */ - } buf; + union ns_mem buf; /* NAND flash "geometry" */ struct nandsin_geometry { @@ -346,12 +344,49 @@ static struct mtd_info *nsmtd; static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; /* + * Allocate array of page pointers and initialize the array to NULL + * pointers. + * + * RETURNS: 0 if success, -ENOMEM if memory alloc fails. + */ +static int alloc_device(struct nandsim *ns) +{ + int i; + + ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); + if (!ns->pages) { + NS_ERR("alloc_map: unable to allocate page array\n"); + return -ENOMEM; + } + for (i = 0; i < ns->geom.pgnum; i++) { + ns->pages[i].byte = NULL; + } + + return 0; +} + +/* + * Free any allocated pages, and free the array of page pointers. + */ +static void free_device(struct nandsim *ns) +{ + int i; + + if (ns->pages) { + for (i = 0; i < ns->geom.pgnum; i++) { + if (ns->pages[i].byte) + kfree(ns->pages[i].byte); + } + vfree(ns->pages); + } +} + +/* * Initialize the nandsim structure. * * RETURNS: 0 if success, -ERRNO if failure. */ -static int -init_nandsim(struct mtd_info *mtd) +static int init_nandsim(struct mtd_info *mtd) { struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); @@ -405,7 +440,7 @@ init_nandsim(struct mtd_info *mtd) } } else { if (ns->geom.totsz <= (128 << 20)) { - ns->geom.pgaddrbytes = 5; + ns->geom.pgaddrbytes = 4; ns->geom.secaddrbytes = 2; } else { ns->geom.pgaddrbytes = 5; @@ -439,23 +474,8 @@ init_nandsim(struct mtd_info *mtd) printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); - /* Map / allocate and initialize the flash image */ -#ifdef CONFIG_NS_ABS_POS - ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); - if (!ns->mem.byte) { - NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", - (void *)CONFIG_NS_ABS_POS); - return -ENOMEM; - } -#else - ns->mem.byte = vmalloc(ns->geom.totszoob); - if (!ns->mem.byte) { - NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n", - ns->geom.totszoob); - return -ENOMEM; - } - memset(ns->mem.byte, 0xFF, ns->geom.totszoob); -#endif + if (alloc_device(ns) != 0) + goto error; /* Allocate / initialize the internal buffer */ ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); @@ -474,11 +494,7 @@ init_nandsim(struct mtd_info *mtd) return 0; error: -#ifdef CONFIG_NS_ABS_POS - iounmap(ns->mem.byte); -#else - vfree(ns->mem.byte); -#endif + free_device(ns); return -ENOMEM; } @@ -486,16 +502,10 @@ error: /* * Free the nandsim structure. */ -static void -free_nandsim(struct nandsim *ns) +static void free_nandsim(struct nandsim *ns) { kfree(ns->buf.byte); - -#ifdef CONFIG_NS_ABS_POS - iounmap(ns->mem.byte); -#else - vfree(ns->mem.byte); -#endif + free_device(ns); return; } @@ -503,8 +513,7 @@ free_nandsim(struct nandsim *ns) /* * Returns the string representation of 'state' state. */ -static char * -get_state_name(uint32_t state) +static char *get_state_name(uint32_t state) { switch (NS_STATE(state)) { case STATE_CMD_READ0: @@ -562,8 +571,7 @@ get_state_name(uint32_t state) * * RETURNS: 1 if wrong command, 0 if right. */ -static int -check_command(int cmd) +static int check_command(int cmd) { switch (cmd) { @@ -589,8 +597,7 @@ check_command(int cmd) /* * Returns state after command is accepted by command number. */ -static uint32_t -get_state_by_command(unsigned command) +static uint32_t get_state_by_command(unsigned command) { switch (command) { case NAND_CMD_READ0: @@ -626,8 +633,7 @@ get_state_by_command(unsigned command) /* * Move an address byte to the correspondent internal register. */ -static inline void -accept_addr_byte(struct nandsim *ns, u_char bt) +static inline void accept_addr_byte(struct nandsim *ns, u_char bt) { uint byte = (uint)bt; @@ -645,8 +651,7 @@ accept_addr_byte(struct nandsim *ns, u_char bt) /* * Switch to STATE_READY state. */ -static inline void -switch_to_ready_state(struct nandsim *ns, u_char status) +static inline void switch_to_ready_state(struct nandsim *ns, u_char status) { NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); @@ -705,8 +710,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) * -1 - several matches. * 0 - operation is found. */ -static int -find_operation(struct nandsim *ns, uint32_t flag) +static int find_operation(struct nandsim *ns, uint32_t flag) { int opsfound = 0; int i, j, idx = 0; @@ -791,14 +795,93 @@ find_operation(struct nandsim *ns, uint32_t flag) } /* + * Returns a pointer to the current page. + */ +static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns) +{ + return &(ns->pages[ns->regs.row]); +} + +/* + * Retuns a pointer to the current byte, within the current page. + */ +static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns) +{ + return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; +} + +/* + * Fill the NAND buffer with data read from the specified page. + */ +static void read_page(struct nandsim *ns, int num) +{ + union ns_mem *mypage; + + mypage = NS_GET_PAGE(ns); + if (mypage->byte == NULL) { + NS_DBG("read_page: page %d not allocated\n", ns->regs.row); + memset(ns->buf.byte, 0xFF, num); + } else { + NS_DBG("read_page: page %d allocated, reading from %d\n", + ns->regs.row, ns->regs.column + ns->regs.off); + memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); + } +} + +/* + * Erase all pages in the specified sector. + */ +static void erase_sector(struct nandsim *ns) +{ + union ns_mem *mypage; + int i; + + mypage = NS_GET_PAGE(ns); + for (i = 0; i < ns->geom.pgsec; i++) { + if (mypage->byte != NULL) { + NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); + kfree(mypage->byte); + mypage->byte = NULL; + } + mypage++; + } +} + +/* + * Program the specified page with the contents from the NAND buffer. + */ +static int prog_page(struct nandsim *ns, int num) +{ + int i; + union ns_mem *mypage; + u_char *pg_off; + + mypage = NS_GET_PAGE(ns); + if (mypage->byte == NULL) { + NS_DBG("prog_page: allocating page %d\n", ns->regs.row); + mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); + if (mypage->byte == NULL) { + NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); + return -1; + } + memset(mypage->byte, 0xFF, ns->geom.pgszoob); + } + + pg_off = NS_PAGE_BYTE_OFF(ns); + for (i = 0; i < num; i++) + pg_off[i] &= ns->buf.byte[i]; + + return 0; +} + +/* * If state has any action bit, perform this action. * * RETURNS: 0 if success, -1 if error. */ -static int -do_state_action(struct nandsim *ns, uint32_t action) +static int do_state_action(struct nandsim *ns, uint32_t action) { - int i, num; + int num; int busdiv = ns->busw == 8 ? 1 : 2; action &= ACTION_MASK; @@ -822,7 +905,7 @@ do_state_action(struct nandsim *ns, uint32_t action) break; } num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; - memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num); + read_page(ns, num); NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", num, NS_RAW_OFFSET(ns) + ns->regs.off); @@ -863,7 +946,7 @@ do_state_action(struct nandsim *ns, uint32_t action) ns->regs.row, NS_RAW_OFFSET(ns)); NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); - memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); + erase_sector(ns); NS_MDELAY(erase_delay); @@ -886,8 +969,8 @@ do_state_action(struct nandsim *ns, uint32_t action) return -1; } - for (i = 0; i < num; i++) - ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i]; + if (prog_page(ns, num) == -1) + return -1; NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); @@ -928,8 +1011,7 @@ do_state_action(struct nandsim *ns, uint32_t action) /* * Switch simulator's state. */ -static void -switch_state(struct nandsim *ns) +static void switch_state(struct nandsim *ns) { if (ns->op) { /* @@ -1070,8 +1152,7 @@ switch_state(struct nandsim *ns) } } -static u_char -ns_nand_read_byte(struct mtd_info *mtd) +static u_char ns_nand_read_byte(struct mtd_info *mtd) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; u_char outb = 0x00; @@ -1144,8 +1225,7 @@ ns_nand_read_byte(struct mtd_info *mtd) return outb; } -static void -ns_nand_write_byte(struct mtd_info *mtd, u_char byte) +static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; @@ -1308,15 +1388,13 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask) ns_nand_write_byte(mtd, cmd); } -static int -ns_device_ready(struct mtd_info *mtd) +static int ns_device_ready(struct mtd_info *mtd) { NS_DBG("device_ready\n"); return 1; } -static uint16_t -ns_nand_read_word(struct mtd_info *mtd) +static uint16_t ns_nand_read_word(struct mtd_info *mtd) { struct nand_chip *chip = (struct nand_chip *)mtd->priv; @@ -1325,8 +1403,7 @@ ns_nand_read_word(struct mtd_info *mtd) return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); } -static void -ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; @@ -1353,8 +1430,7 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } } -static void -ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; @@ -1407,8 +1483,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) return; } -static int -ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); @@ -1436,14 +1511,12 @@ static int __init ns_init_module(void) } /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ - nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) + nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) + sizeof(struct nandsim), GFP_KERNEL); if (!nsmtd) { NS_ERR("unable to allocate core structures.\n"); return -ENOMEM; } - memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) + - sizeof(struct nandsim)); chip = (struct nand_chip *)(nsmtd + 1); nsmtd->priv = (void *)chip; nand = (struct nandsim *)(chip + 1); diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 039c759cfbf..fd7a8d5ba29 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -56,7 +56,7 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); } else ccr |= NDFC_CCR_RESET_CE; - writel(ccr, ndfc->ndfcbase + NDFC_CCR); + __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); } static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index f8c49645324..9189ec8f243 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/rslib.h> +#include <linux/bitrev.h> #include <linux/module.h> #include <linux/mtd/compatmac.h> #include <linux/mtd/mtd.h> @@ -152,47 +153,6 @@ static struct nand_ecclayout rtc_from4_nand_oobinfo = { .oobfree = {{32, 32}} }; -/* Aargh. I missed the reversed bit order, when I - * was talking to Renesas about the FPGA. - * - * The table is used for bit reordering and inversion - * of the ecc byte which we get from the FPGA - */ -static uint8_t revbits[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, -}; - #endif /* @@ -397,7 +357,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha /* Read the syndrom pattern from the FPGA and correct the bitorder */ rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); for (i = 0; i < 8; i++) { - ecc[i] = revbits[(*rs_ecc) & 0xFF]; + ecc[i] = bitrev8(*rs_ecc); rs_ecc++; } @@ -496,7 +456,7 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, rtn = nand_do_read(mtd, page, len, &retlen, buf); /* if read failed or > 1-bit error corrected */ - if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) { + if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) er_stat |= 1 << 1; kfree(buf); } diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index ff5cef24d5b..8b3203571ee 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -283,7 +283,7 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - + if (cmd == NAND_CMD_NONE) return; diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index b5a5f8da472..4b1ba4fcfcd 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -57,17 +57,16 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); - nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); + nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); if (!nftl) { printk(KERN_WARNING "NFTL: out of memory for data structures\n"); return; } - memset(nftl, 0, sizeof(*nftl)); nftl->mbd.mtd = mtd; nftl->mbd.devnum = -1; - nftl->mbd.blksize = 512; + nftl->mbd.tr = tr; if (NFTL_mount(nftl) < 0) { @@ -147,10 +146,9 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, ops.ooblen = len; ops.oobbuf = buf; ops.datbuf = NULL; - ops.len = len; res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops); - *retlen = ops.retlen; + *retlen = ops.oobretlen; return res; } @@ -168,10 +166,9 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, ops.ooblen = len; ops.oobbuf = buf; ops.datbuf = NULL; - ops.len = len; res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops); - *retlen = ops.retlen; + *retlen = ops.oobretlen; return res; } @@ -797,6 +794,7 @@ static struct mtd_blktrans_ops nftl_tr = { .name = "nftl", .major = NFTL_MAJOR, .part_bits = NFTL_PARTN_BITS, + .blksize = 512, .getgeo = nftl_getgeo, .readsect = nftl_readblock, #ifdef CONFIG_NFTL_RW diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index af06a80f44d..3d44d040a47 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -45,12 +45,10 @@ static int __devinit generic_onenand_probe(struct device *dev) unsigned long size = res->end - res->start + 1; int err; - info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL); + info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); if (!info) return -ENOMEM; - memset(info, 0, sizeof(struct onenand_info)); - if (!request_mem_region(res->start, size, dev->driver->name)) { err = -EBUSY; goto out_free_info; @@ -63,6 +61,7 @@ static int __devinit generic_onenand_probe(struct device *dev) } info->onenand.mmcontrol = pdata->mmcontrol; + info->onenand.irq = platform_get_irq(pdev, 0); info->mtd.name = pdev->dev.bus_id; info->mtd.priv = &info->onenand; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 8ed68b28afe..2da6bb26353 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/mtd/mtd.h> #include <linux/mtd/onenand.h> @@ -191,8 +192,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le struct onenand_chip *this = mtd->priv; int value, readcmd = 0, block_cmd = 0; int block, page; - /* Now we use page size operation */ - int sectors = 4, count = 4; /* Address translation */ switch (cmd) { @@ -244,6 +243,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le } if (page != -1) { + /* Now we use page size operation */ + int sectors = 4, count = 4; int dataram; switch (cmd) { @@ -297,7 +298,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) unsigned long timeout; unsigned int flags = ONENAND_INT_MASTER; unsigned int interrupt = 0; - unsigned int ctrl, ecc; + unsigned int ctrl; /* The 20 msec is enough */ timeout = jiffies + msecs_to_jiffies(20); @@ -309,7 +310,6 @@ static int onenand_wait(struct mtd_info *mtd, int state) if (state != FL_READING) cond_resched(); - touch_softlockup_watchdog(); } /* To get correct interrupt status in timeout case */ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); @@ -317,28 +317,126 @@ static int onenand_wait(struct mtd_info *mtd, int state) ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); if (ctrl & ONENAND_CTRL_ERROR) { - /* It maybe occur at initial bad block */ DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); - /* Clear other interrupt bits for preventing ECC error */ - interrupt &= ONENAND_INT_MASTER; - } - - if (ctrl & ONENAND_CTRL_LOCK) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl); - return -EACCES; + if (ctrl & ONENAND_CTRL_LOCK) + DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n"); + return ctrl; } if (interrupt & ONENAND_INT_READ) { - ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); - if (ecc & ONENAND_ECC_2BIT_ALL) { + int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); + if (ecc) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); - return -EBADMSG; + if (ecc & ONENAND_ECC_2BIT_ALL) { + mtd->ecc_stats.failed++; + return ecc; + } else if (ecc & ONENAND_ECC_1BIT_ALL) + mtd->ecc_stats.corrected++; } } return 0; } +/* + * onenand_interrupt - [DEFAULT] onenand interrupt handler + * @param irq onenand interrupt number + * @param dev_id interrupt data + * + * complete the work + */ +static irqreturn_t onenand_interrupt(int irq, void *data) +{ + struct onenand_chip *this = (struct onenand_chip *) data; + + /* To handle shared interrupt */ + if (!this->complete.done) + complete(&this->complete); + + return IRQ_HANDLED; +} + +/* + * onenand_interrupt_wait - [DEFAULT] wait until the command is done + * @param mtd MTD device structure + * @param state state to select the max. timeout value + * + * Wait for command done. + */ +static int onenand_interrupt_wait(struct mtd_info *mtd, int state) +{ + struct onenand_chip *this = mtd->priv; + + wait_for_completion(&this->complete); + + return onenand_wait(mtd, state); +} + +/* + * onenand_try_interrupt_wait - [DEFAULT] try interrupt wait + * @param mtd MTD device structure + * @param state state to select the max. timeout value + * + * Try interrupt based wait (It is used one-time) + */ +static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state) +{ + struct onenand_chip *this = mtd->priv; + unsigned long remain, timeout; + + /* We use interrupt wait first */ + this->wait = onenand_interrupt_wait; + + timeout = msecs_to_jiffies(100); + remain = wait_for_completion_timeout(&this->complete, timeout); + if (!remain) { + printk(KERN_INFO "OneNAND: There's no interrupt. " + "We use the normal wait\n"); + + /* Release the irq */ + free_irq(this->irq, this); + + this->wait = onenand_wait; + } + + return onenand_wait(mtd, state); +} + +/* + * onenand_setup_wait - [OneNAND Interface] setup onenand wait method + * @param mtd MTD device structure + * + * There's two method to wait onenand work + * 1. polling - read interrupt status register + * 2. interrupt - use the kernel interrupt method + */ +static void onenand_setup_wait(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + int syscfg; + + init_completion(&this->complete); + + if (this->irq <= 0) { + this->wait = onenand_wait; + return; + } + + if (request_irq(this->irq, &onenand_interrupt, + IRQF_SHARED, "onenand", this)) { + /* If we can't get irq, use the normal wait */ + this->wait = onenand_wait; + return; + } + + /* Enable interrupt */ + syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); + syscfg |= ONENAND_SYS_CFG1_IOBE; + this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); + + this->wait = onenand_try_interrupt_wait; +} + /** * onenand_bufferram_offset - [DEFAULT] BufferRAM offset * @param mtd MTD data structure @@ -609,9 +707,10 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; + struct mtd_ecc_stats stats; int read = 0, column; int thislen; - int ret = 0; + int ret = 0, boundary = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); @@ -627,38 +726,61 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, /* TODO handling oob */ - while (read < len) { - thislen = min_t(int, mtd->writesize, len - read); - - column = from & (mtd->writesize - 1); - if (column + thislen > mtd->writesize) - thislen = mtd->writesize - column; - - if (!onenand_check_bufferram(mtd, from)) { - this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); - - ret = this->wait(mtd, FL_READING); - /* First copy data and check return value for ECC handling */ - onenand_update_bufferram(mtd, from, 1); - } - - this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); - - read += thislen; - - if (read == len) - break; - - if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); - goto out; - } - - from += thislen; - buf += thislen; - } + stats = mtd->ecc_stats; + + /* Read-while-load method */ + + /* Do first load to bufferRAM */ + if (read < len) { + if (!onenand_check_bufferram(mtd, from)) { + this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); + ret = this->wait(mtd, FL_READING); + onenand_update_bufferram(mtd, from, !ret); + } + } + + thislen = min_t(int, mtd->writesize, len - read); + column = from & (mtd->writesize - 1); + if (column + thislen > mtd->writesize) + thislen = mtd->writesize - column; + + while (!ret) { + /* If there is more to load then start next load */ + from += thislen; + if (read + thislen < len) { + this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); + /* + * Chip boundary handling in DDP + * Now we issued chip 1 read and pointed chip 1 + * bufferam so we have to point chip 0 bufferam. + */ + if (this->device_id & ONENAND_DEVICE_IS_DDP && + unlikely(from == (this->chipsize >> 1))) { + this->write_word(0, this->base + ONENAND_REG_START_ADDRESS2); + boundary = 1; + } else + boundary = 0; + ONENAND_SET_PREV_BUFFERRAM(this); + } + /* While load is going, read from last bufferRAM */ + this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); + /* See if we are done */ + read += thislen; + if (read == len) + break; + /* Set up for next read from bufferRAM */ + if (unlikely(boundary)) + this->write_word(0x8000, this->base + ONENAND_REG_START_ADDRESS2); + ONENAND_SET_NEXT_BUFFERRAM(this); + buf += thislen; + thislen = min_t(int, mtd->writesize, len - read); + column = 0; + cond_resched(); + /* Now wait for load */ + ret = this->wait(mtd, FL_READING); + onenand_update_bufferram(mtd, from, !ret); + } -out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); @@ -668,7 +790,14 @@ out: * retlen == desired len and result == -EBADMSG */ *retlen = read; - return ret; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + if (ret) + return ret; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** @@ -705,6 +834,8 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, column = from & (mtd->oobsize - 1); while (read < len) { + cond_resched(); + thislen = mtd->oobsize - column; thislen = min_t(int, thislen, len); @@ -717,16 +848,16 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret); + goto out; + } + read += thislen; if (read == len) break; - if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); - goto out; - } - buf += thislen; /* Read more? */ @@ -756,8 +887,8 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, { BUG_ON(ops->mode != MTD_OOB_PLACE); - return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->len, - &ops->retlen, ops->oobbuf); + return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen, + &ops->oobretlen, ops->oobbuf); } #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE @@ -804,6 +935,10 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) void __iomem *dataram0, *dataram1; int ret = 0; + /* In partial page write, just skip it */ + if ((addr & (mtd->writesize - 1)) != 0) + return 0; + this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); ret = this->wait(mtd, FL_READING); @@ -826,7 +961,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) #define onenand_verify_oob(...) (0) #endif -#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) +#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** * onenand_write - [MTD Interface] write buffer to FLASH @@ -844,6 +979,7 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, struct onenand_chip *this = mtd->priv; int written = 0; int ret = 0; + int column, subpage; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); @@ -862,45 +998,63 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } + column = to & (mtd->writesize - 1); + subpage = column || (len & (mtd->writesize - 1)); + /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->writesize, len - written); - - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); + int bytes = mtd->writesize; + int thislen = min_t(int, bytes, len - written); + u_char *wbuf = (u_char *) buf; + + cond_resched(); + + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes); + + /* Partial page write */ + if (subpage) { + bytes = min_t(int, bytes - column, (int) len); + memset(this->page_buf, 0xff, mtd->writesize); + memcpy(this->page_buf + column, buf, bytes); + wbuf = this->page_buf; + /* Even though partial write, we need page size */ + thislen = mtd->writesize; + } - this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); + this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); - onenand_update_bufferram(mtd, to, 1); + /* In partial page write we don't update bufferram */ + onenand_update_bufferram(mtd, to, !subpage); ret = this->wait(mtd, FL_WRITING); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); - goto out; + break; } - written += thislen; - /* Only check verify write turn on */ - ret = onenand_verify_page(mtd, (u_char *) buf, to); + ret = onenand_verify_page(mtd, (u_char *) wbuf, to); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); - goto out; + break; } + written += thislen; + if (written == len) break; + column = 0; to += thislen; buf += thislen; } -out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); @@ -944,6 +1098,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, while (written < len) { int thislen = min_t(int, mtd->oobsize, len - written); + cond_resched(); + column = to & (mtd->oobsize - 1); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); @@ -999,8 +1155,8 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, { BUG_ON(ops->mode != MTD_OOB_PLACE); - return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->len, - &ops->retlen, ops->oobbuf); + return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen, + &ops->oobretlen, ops->oobbuf); } /** @@ -1071,6 +1227,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASING; while (len) { + cond_resched(); /* Check if we have a bad block, we do not erase bad blocks */ if (onenand_block_checkbad(mtd, addr, 0, 0)) { @@ -1084,10 +1241,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) ret = this->wait(mtd, FL_ERASING); /* Check, if it is write protected */ if (ret) { - if (ret == -EPERM) - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n"); - else - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; goto erase_exit; @@ -1129,7 +1283,6 @@ static void onenand_sync(struct mtd_info *mtd) onenand_release_device(mtd); } - /** * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad * @param mtd MTD device structure @@ -1196,32 +1349,38 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) } /** - * onenand_unlock - [MTD Interface] Unlock block(s) + * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s) * @param mtd MTD device structure * @param ofs offset relative to mtd start - * @param len number of bytes to unlock + * @param len number of bytes to lock or unlock * - * Unlock one or more blocks + * Lock or unlock one or more blocks */ -static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd) { struct onenand_chip *this = mtd->priv; int start, end, block, value, status; + int wp_status_mask; start = ofs >> this->erase_shift; end = len >> this->erase_shift; + if (cmd == ONENAND_CMD_LOCK) + wp_status_mask = ONENAND_WP_LS; + else + wp_status_mask = ONENAND_WP_US; + /* Continuous lock scheme */ if (this->options & ONENAND_HAS_CONT_LOCK) { /* Set start block address */ this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); /* Set end block address */ this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); - /* Write unlock command */ - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); + /* Write lock command */ + this->command(mtd, cmd, 0, 0); /* There's no return value */ - this->wait(mtd, FL_UNLOCKING); + this->wait(mtd, FL_LOCKING); /* Sanity check */ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) @@ -1230,7 +1389,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) /* Check lock status */ status = this->read_word(this->base + ONENAND_REG_WP_STATUS); - if (!(status & ONENAND_WP_US)) + if (!(status & wp_status_mask)) printk(KERN_ERR "wp status = 0x%x\n", status); return 0; @@ -1246,11 +1405,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); /* Set start block address */ this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); - /* Write unlock command */ - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); + /* Write lock command */ + this->command(mtd, cmd, 0, 0); /* There's no return value */ - this->wait(mtd, FL_UNLOCKING); + this->wait(mtd, FL_LOCKING); /* Sanity check */ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) @@ -1259,7 +1418,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) /* Check lock status */ status = this->read_word(this->base + ONENAND_REG_WP_STATUS); - if (!(status & ONENAND_WP_US)) + if (!(status & wp_status_mask)) printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); } @@ -1267,6 +1426,32 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) } /** + * onenand_lock - [MTD Interface] Lock block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to unlock + * + * Lock one or more blocks + */ +static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); +} + +/** + * onenand_unlock - [MTD Interface] Unlock block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to unlock + * + * Unlock one or more blocks + */ +static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); +} + +/** * onenand_check_lock_status - [OneNAND Interface] Check lock status * @param this onenand chip data structure * @@ -1310,7 +1495,7 @@ static int onenand_unlock_all(struct mtd_info *mtd) this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); /* There's no return value */ - this->wait(mtd, FL_UNLOCKING); + this->wait(mtd, FL_LOCKING); /* Sanity check */ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) @@ -1334,7 +1519,7 @@ static int onenand_unlock_all(struct mtd_info *mtd) return 0; } - mtd->unlock(mtd, 0x0, this->chipsize); + onenand_unlock(mtd, 0x0, this->chipsize); return 0; } @@ -1762,7 +1947,7 @@ static int onenand_probe(struct mtd_info *mtd) /* Read manufacturer and device IDs from Register */ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); - ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID); + ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); /* Check OneNAND device */ if (maf_id != bram_maf_id || dev_id != bram_dev_id) @@ -1846,7 +2031,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) if (!this->command) this->command = onenand_command; if (!this->wait) - this->wait = onenand_wait; + onenand_setup_wait(mtd); if (!this->read_bufferram) this->read_bufferram = onenand_read_bufferram; @@ -1883,23 +2068,30 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) init_waitqueue_head(&this->wq); spin_lock_init(&this->chip_lock); + /* + * Allow subpage writes up to oobsize. + */ switch (mtd->oobsize) { case 64: this->ecclayout = &onenand_oob_64; + mtd->subpage_sft = 2; break; case 32: this->ecclayout = &onenand_oob_32; + mtd->subpage_sft = 1; break; default: printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", mtd->oobsize); + mtd->subpage_sft = 0; /* To prevent kernel oops */ this->ecclayout = &onenand_oob_32; break; } + this->subpagesize = mtd->writesize >> mtd->subpage_sft; mtd->ecclayout = this->ecclayout; /* Fill in remaining MTD driver data */ @@ -1922,7 +2114,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; #endif mtd->sync = onenand_sync; - mtd->lock = NULL; + mtd->lock = onenand_lock; mtd->unlock = onenand_unlock; mtd->suspend = onenand_suspend; mtd->resume = onenand_resume; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 1b00dac3d7d..98f8fd1c637 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -93,13 +93,15 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs, readlen, &retlen, &buf[0]); - if (ret) + /* If it is a initial bad block, just ignore it */ + if (ret && !(ret & ONENAND_CTRL_LOAD)) return ret; if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); + mtd->ecc_stats.badblocks++; break; } } @@ -177,14 +179,12 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) int len, ret = 0; len = mtd->size >> (this->erase_shift + 2); - /* Allocate memory (2bit per block) */ - bbm->bbt = kmalloc(len, GFP_KERNEL); + /* Allocate memory (2bit per block) and clear the memory bad block table */ + bbm->bbt = kzalloc(len, GFP_KERNEL); if (!bbm->bbt) { printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); return -ENOMEM; } - /* Clear the memory bad block table */ - memset(bbm->bbt, 0x00, len); /* Set the bad block position */ bbm->badblockpos = ONENAND_BADBLOCK_POS; @@ -230,14 +230,12 @@ int onenand_default_bbt(struct mtd_info *mtd) struct onenand_chip *this = mtd->priv; struct bbm_info *bbm; - this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL); + this->bbm = kzalloc(sizeof(struct bbm_info), GFP_KERNEL); if (!this->bbm) return -ENOMEM; bbm = this->bbm; - memset(bbm, 0, sizeof(struct bbm_info)); - /* 1KB page has same configuration as 2KB page */ if (!bbm->badblock_pattern) bbm->badblock_pattern = &largepage_memorybased; diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 5b58523e4d4..035cd9b0cc0 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -96,7 +96,19 @@ static int parse_redboot_partitions(struct mtd_info *master, */ if (swab32(buf[i].size) == master->erasesize) { int j; - for (j = 0; j < numslots && buf[j].name[0] != 0xff; ++j) { + for (j = 0; j < numslots; ++j) { + + /* A single 0xff denotes a deleted entry. + * Two of them in a row is the end of the table. + */ + if (buf[j].name[0] == 0xff) { + if (buf[j].name[1] == 0xff) { + break; + } else { + continue; + } + } + /* The unsigned long fields were written with the * wrong byte sex, name and pad have no byte sex. */ @@ -110,6 +122,9 @@ static int parse_redboot_partitions(struct mtd_info *master, } } break; + } else { + /* re-calculate of real numslots */ + numslots = buf[i].size / sizeof(struct fis_image_desc); } } if (i == numslots) { @@ -123,8 +138,13 @@ static int parse_redboot_partitions(struct mtd_info *master, for (i = 0; i < numslots; i++) { struct fis_list *new_fl, **prev; - if (buf[i].name[0] == 0xff) - continue; + if (buf[i].name[0] == 0xff) { + if (buf[i].name[1] == 0xff) { + break; + } else { + continue; + } + } if (!redboot_checksum(&buf[i])) break; @@ -165,15 +185,13 @@ static int parse_redboot_partitions(struct mtd_info *master, } } #endif - parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL); + parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL); if (!parts) { ret = -ENOMEM; goto out; } - memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen); - nullname = (char *)&parts[nrparts]; #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED if (nulllen > 0) { diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 0f3baa5d9c2..d4b1ba8f23e 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -787,7 +787,6 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (scan_header(part) == 0) { part->mbd.size = part->sector_count; - part->mbd.blksize = SECTOR_SIZE; part->mbd.tr = tr; part->mbd.devnum = -1; if (!(mtd->flags & MTD_WRITEABLE)) @@ -829,6 +828,8 @@ struct mtd_blktrans_ops rfd_ftl_tr = { .name = "rfd", .major = RFD_FTL_MAJOR, .part_bits = PART_BITS, + .blksize = SECTOR_SIZE, + .readsect = rfd_ftl_readsect, .writesect = rfd_ftl_writesect, .getgeo = rfd_ftl_getgeo, diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 79d3bb659bf..a5f3d60047d 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -172,13 +172,12 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) ops.mode = MTD_OOB_RAW; ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - ops.len = OOB_SIZE; + ops.ooblen = OOB_SIZE; ops.oobbuf = buf; ops.datbuf = NULL; ret = mtd->read_oob(mtd, offs, &ops); - if (ret < 0 || ops.retlen != OOB_SIZE) + if (ret < 0 || ops.oobretlen != OOB_SIZE) return -1; return 0; @@ -312,7 +311,6 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->mbd.mtd = mtd; ssfdc->mbd.devnum = -1; - ssfdc->mbd.blksize = SECTOR_SIZE; ssfdc->mbd.tr = tr; ssfdc->mbd.readonly = 1; @@ -447,6 +445,7 @@ static struct mtd_blktrans_ops ssfdcr_tr = { .name = "ssfdc", .major = SSFDCR_MAJOR, .part_bits = SSFDCR_PARTN_BITS, + .blksize = SECTOR_SIZE, .getgeo = ssfdcr_getgeo, .readsect = ssfdcr_readsect, .add_mtd = ssfdcr_add_mtd, diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 458dd9f830c..6f93a765e56 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -617,13 +617,15 @@ rx_next: * this round of polling */ if (rx_work) { + unsigned long flags; + if (cpr16(IntrStatus) & cp_rx_intr_mask) goto rx_status_loop; - local_irq_disable(); + local_irq_save(flags); cpw16_f(IntrMask, cp_intr_mask); __netif_rx_complete(dev); - local_irq_enable(); + local_irq_restore(flags); return 0; /* done */ } @@ -763,17 +765,18 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) struct cp_private *cp = netdev_priv(dev); unsigned entry; u32 eor, flags; + unsigned long intr_flags; #if CP_VLAN_TAG_USED u32 vlan_tag = 0; #endif int mss = 0; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, intr_flags); /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, intr_flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); return 1; @@ -906,7 +909,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, intr_flags); cpw8(TxPoll, NormalTxPoll); dev->trans_start = jiffies; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 8236f26ffd4..640d7ca2ebc 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1066,8 +1066,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) short length = skb->len; dev->trans_start = jiffies; - DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%x) called\n", dev->name, - skb->len, (unsigned int)skb->data)); + DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n", + dev->name, skb->len, skb->data)); if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) @@ -1246,7 +1246,8 @@ struct net_device * __init i82596_probe(int unit) dev->priv = (void *)(dev->mem_start); lp = dev->priv; - DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", + DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), " + "lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, sizeof(struct i596_private), (unsigned long)&lp->scb)); memset((void *) lp, 0, sizeof(struct i596_private)); diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 602ed31a5dd..9305eb9b1b9 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -349,22 +349,11 @@ static void __init trif_probe2(int unit) #endif -/* - * The loopback device is global so it can be directly referenced - * by the network code. Also, it must be first on device list. - */ -extern int loopback_init(void); - /* Statically configured drivers -- order matters here. */ static int __init net_olddevs_init(void) { int num; - if (loopback_init()) { - printk(KERN_ERR "Network loopback device setup failed\n"); - } - - #ifdef CONFIG_SBNI for (num = 0; num < 8; ++num) sbni_probe(num); diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 8ebd68e2af9..dd698b033a6 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -780,12 +780,10 @@ static struct ethtool_ops ep93xx_ethtool_ops = { struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) { struct net_device *dev; - struct ep93xx_priv *ep; dev = alloc_etherdev(sizeof(struct ep93xx_priv)); if (dev == NULL) return NULL; - ep = netdev_priv(dev); memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN); @@ -840,9 +838,9 @@ static int ep93xx_eth_probe(struct platform_device *pdev) struct ep93xx_priv *ep; int err; - data = pdev->dev.platform_data; if (pdev == NULL) return -ENODEV; + data = pdev->dev.platform_data; dev = ep93xx_dev_alloc(data); if (dev == NULL) { diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 474a4e3438d..303a8d94ad4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -110,6 +110,11 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl); static void b44_halt(struct b44 *); static void b44_init_rings(struct b44 *); + +#define B44_FULL_RESET 1 +#define B44_FULL_RESET_SKIP_PHY 2 +#define B44_PARTIAL_RESET 3 + static void b44_init_hw(struct b44 *, int); static int dma_desc_align_mask; @@ -752,7 +757,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dest_idx * sizeof(dest_desc), DMA_BIDIRECTIONAL); - pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, + pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr), RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); } @@ -879,12 +884,14 @@ static int b44_poll(struct net_device *netdev, int *budget) } if (bp->istat & ISTAT_ERRORS) { - spin_lock_irq(&bp->lock); + unsigned long flags; + + spin_lock_irqsave(&bp->lock, flags); b44_halt(bp); b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); netif_wake_queue(bp->dev); - spin_unlock_irq(&bp->lock); + spin_unlock_irqrestore(&bp->lock, flags); done = 1; } @@ -952,7 +959,7 @@ static void b44_tx_timeout(struct net_device *dev) b44_halt(bp); b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET); spin_unlock_irq(&bp->lock); @@ -1069,7 +1076,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) b44_halt(bp); dev->mtu = new_mtu; b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET); spin_unlock_irq(&bp->lock); b44_enable_ints(bp); @@ -1366,12 +1373,12 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) * packet processing. Invoked with bp->lock held. */ static void __b44_set_rx_mode(struct net_device *); -static void b44_init_hw(struct b44 *bp, int full_reset) +static void b44_init_hw(struct b44 *bp, int reset_kind) { u32 val; b44_chip_reset(bp); - if (full_reset) { + if (reset_kind == B44_FULL_RESET) { b44_phy_reset(bp); b44_setup_phy(bp); } @@ -1388,7 +1395,10 @@ static void b44_init_hw(struct b44 *bp, int full_reset) bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ - if (full_reset) { + if (reset_kind == B44_PARTIAL_RESET) { + bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | + (bp->rx_offset << DMARX_CTRL_ROSHIFT))); + } else { bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | @@ -1399,9 +1409,6 @@ static void b44_init_hw(struct b44 *bp, int full_reset) bp->rx_prod = bp->rx_pending; bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); - } else { - bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | - (bp->rx_offset << DMARX_CTRL_ROSHIFT))); } val = br32(bp, B44_ENET_CTRL); @@ -1418,7 +1425,7 @@ static int b44_open(struct net_device *dev) goto out; b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET); b44_check_phy(bp); @@ -1627,7 +1634,7 @@ static int b44_close(struct net_device *dev) netif_poll_enable(dev); if (bp->flags & B44_FLAG_WOL_ENABLE) { - b44_init_hw(bp, 0); + b44_init_hw(bp, B44_PARTIAL_RESET); b44_setup_wol(bp); } @@ -1903,7 +1910,7 @@ static int b44_set_ringparam(struct net_device *dev, b44_halt(bp); b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET); netif_wake_queue(bp->dev); spin_unlock_irq(&bp->lock); @@ -1946,7 +1953,7 @@ static int b44_set_pauseparam(struct net_device *dev, if (bp->flags & B44_FLAG_PAUSE_AUTO) { b44_halt(bp); b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET); } else { __b44_set_flow_ctrl(bp, bp->flags); } @@ -2302,7 +2309,7 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) free_irq(dev->irq, dev); if (bp->flags & B44_FLAG_WOL_ENABLE) { - b44_init_hw(bp, 0); + b44_init_hw(bp, B44_PARTIAL_RESET); b44_setup_wol(bp); } pci_disable_device(pdev); @@ -2313,21 +2320,32 @@ static int b44_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct b44 *bp = netdev_priv(dev); + int rc = 0; pci_restore_state(pdev); - pci_enable_device(pdev); + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR PFX "%s: pci_enable_device failed\n", + dev->name); + return rc; + } + pci_set_master(pdev); if (!netif_running(dev)) return 0; - if (request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev)) + rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); + if (rc) { printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); + pci_disable_device(pdev); + return rc; + } spin_lock_irq(&bp->lock); b44_init_rings(bp); - b44_init_hw(bp, 1); + b44_init_hw(bp, B44_FULL_RESET); netif_device_attach(bp->dev); spin_unlock_irq(&bp->lock); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 7d824cf8ee2..ee7b75b976b 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -57,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.5.1" -#define DRV_MODULE_RELDATE "November 15, 2006" +#define DRV_MODULE_VERSION "1.5.5" +#define DRV_MODULE_RELDATE "February 1, 2007" #define RUN_AT(x) (jiffies + (x)) @@ -217,9 +217,16 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp) u32 diff; smp_mb(); - diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons); - if (diff > MAX_TX_DESC_CNT) - diff = (diff & MAX_TX_DESC_CNT) - 1; + + /* The ring uses 256 indices for 255 entries, one of them + * needs to be skipped. + */ + diff = bp->tx_prod - bp->tx_cons; + if (unlikely(diff >= TX_DESC_CNT)) { + diff &= 0xffff; + if (diff == TX_DESC_CNT) + diff = MAX_TX_DESC_CNT; + } return (bp->tx_ring_size - diff); } @@ -1338,8 +1345,6 @@ bnx2_init_copper_phy(struct bnx2 *bp) { u32 val; - bp->phy_flags |= PHY_CRC_FIX_FLAG; - if (bp->phy_flags & PHY_CRC_FIX_FLAG) { bnx2_write_phy(bp, 0x18, 0x0c00); bnx2_write_phy(bp, 0x17, 0x000a); @@ -1351,6 +1356,14 @@ bnx2_init_copper_phy(struct bnx2 *bp) bnx2_write_phy(bp, 0x18, 0x0400); } + if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) { + bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, + MII_BNX2_DSP_EXPAND_REG | 0x8); + bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val); + val &= ~(1 << 8); + bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val); + } + if (bp->dev->mtu > 1500) { /* Set extended packet length bit */ bnx2_write_phy(bp, 0x18, 0x7); @@ -3078,7 +3091,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, int buf_size) { u32 written, offset32, len32; - u8 *buf, start[4], end[4], *flash_buffer = NULL; + u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL; int rc = 0; int align_start, align_end; @@ -3089,7 +3102,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, if ((align_start = (offset32 & 3))) { offset32 &= ~3; - len32 += align_start; + len32 += (4 - align_start); if ((rc = bnx2_nvram_read(bp, offset32, start, 4))) return rc; } @@ -3106,16 +3119,17 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, } if (align_start || align_end) { - buf = kmalloc(len32, GFP_KERNEL); - if (buf == 0) + align_buf = kmalloc(len32, GFP_KERNEL); + if (align_buf == NULL) return -ENOMEM; if (align_start) { - memcpy(buf, start, 4); + memcpy(align_buf, start, 4); } if (align_end) { - memcpy(buf + len32 - 4, end, 4); + memcpy(align_buf + len32 - 4, end, 4); } - memcpy(buf + align_start, data_buf, buf_size); + memcpy(align_buf + align_start, data_buf, buf_size); + buf = align_buf; } if (bp->flash_info->buffered == 0) { @@ -3249,11 +3263,8 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, } nvram_write_end: - if (bp->flash_info->buffered == 0) - kfree(flash_buffer); - - if (align_start || align_end) - kfree(buf); + kfree(flash_buffer); + kfree(align_buf); return rc; } @@ -3998,7 +4009,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) if (!skb) return -ENOMEM; packet = skb_put(skb, pkt_size); - memcpy(packet, bp->mac_addr, 6); + memcpy(packet, bp->dev->dev_addr, 6); memset(packet + 6, 0x0, 8); for (i = 14; i < pkt_size; i++) packet[i] = (unsigned char) (i & 0xff); @@ -5638,6 +5649,44 @@ poll_bnx2(struct net_device *dev) } #endif +static void __devinit +bnx2_get_5709_media(struct bnx2 *bp) +{ + u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL); + u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID; + u32 strap; + + if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) + return; + else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) { + bp->phy_flags |= PHY_SERDES_FLAG; + return; + } + + if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE) + strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21; + else + strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8; + + if (PCI_FUNC(bp->pdev->devfn) == 0) { + switch (strap) { + case 0x4: + case 0x5: + case 0x6: + bp->phy_flags |= PHY_SERDES_FLAG; + return; + } + } else { + switch (strap) { + case 0x1: + case 0x2: + case 0x4: + bp->phy_flags |= PHY_SERDES_FLAG; + return; + } + } +} + static int __devinit bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) { @@ -5804,9 +5853,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE); if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) == - BNX2_SHM_HDR_SIGNATURE_SIG) - bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0); - else + BNX2_SHM_HDR_SIGNATURE_SIG) { + u32 off = PCI_FUNC(pdev->devfn) << 2; + + bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off); + } else bp->shmem_base = HOST_VIEW_SHMEM_BASE; /* Get the permanent MAC address. First we need to make sure the @@ -5858,10 +5909,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->phy_addr = 1; /* Disable WOL support if we are running on a SERDES chip. */ - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - if (CHIP_BOND_ID(bp) != BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) - bp->phy_flags |= PHY_SERDES_FLAG; - } else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) + if (CHIP_NUM(bp) == CHIP_NUM_5709) + bnx2_get_5709_media(bp); + else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) bp->phy_flags |= PHY_SERDES_FLAG; if (bp->phy_flags & PHY_SERDES_FLAG) { @@ -5873,7 +5923,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG; } - } + } else if (CHIP_NUM(bp) == CHIP_NUM_5706 || + CHIP_NUM(bp) == CHIP_NUM_5708) + bp->phy_flags |= PHY_CRC_FIX_FLAG; + else if (CHIP_ID(bp) == CHIP_ID_5709_A0) + bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG; if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 13b6f9b11e0..ccbdf81c659 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6288,6 +6288,10 @@ struct l2_fhdr { #define BCM5708S_TX_ACTL3 0x17 +#define MII_BNX2_DSP_RW_PORT 0x15 +#define MII_BNX2_DSP_ADDRESS 0x17 +#define MII_BNX2_DSP_EXPAND_REG 0x0f00 + #define MIN_ETHERNET_PACKET_SIZE 60 #define MAX_ETHERNET_PACKET_SIZE 1514 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014 @@ -6489,6 +6493,7 @@ struct bnx2 { #define PHY_INT_MODE_MASK_FLAG 0x300 #define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100 #define PHY_INT_MODE_LINK_READY_FLAG 0x200 +#define PHY_DIS_EARLY_DAC_FLAG 0x400 u32 chip_id; /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ @@ -6512,6 +6517,7 @@ struct bnx2 { #define CHIP_ID_5708_A0 0x57080000 #define CHIP_ID_5708_B0 0x57081000 #define CHIP_ID_5708_B1 0x57081010 +#define CHIP_ID_5709_A0 0x57090000 #define CHIP_BOND_ID(bp) (((bp)->chip_id) & 0xf) diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index dc434fb6da8..0978c9ac6d2 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -151,8 +151,8 @@ struct slave { struct slave *next; struct slave *prev; int delay; - u32 jiffies; - u32 last_arp_rx; + unsigned long jiffies; + unsigned long last_arp_rx; s8 link; /* one of BOND_LINK_XXXX */ s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; @@ -242,7 +242,8 @@ extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slav return bond->params.arp_validate & (1 << slave->state); } -extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave) +extern inline unsigned long slave_last_rx(struct bonding *bond, + struct slave *slave) { if (slave_do_arp_validate(bond, slave)) return slave->last_arp_rx; diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index c7731b6f9de..82fed1dd500 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -170,9 +170,10 @@ static struct cphy *my3126_phy_create(adapter_t *adapter, { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); - if (cphy) - cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); + if (!cphy) + return NULL; + cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index c2ae2a24629..0cefef5e3f0 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2718,12 +2718,11 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); -#ifdef CONFIG_E100_NAPI if (netif_running(netdev)) netif_poll_disable(nic->netdev); -#endif del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); + netif_device_detach(netdev); pci_save_state(pdev); @@ -2736,6 +2735,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) } pci_disable_device(pdev); + free_irq(pdev->irq, netdev); pci_set_power_state(pdev, PCI_D3hot); return 0; @@ -2759,16 +2759,13 @@ static int e100_resume(struct pci_dev *pdev) } #endif /* CONFIG_PM */ - static void e100_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); -#ifdef CONFIG_E100_NAPI if (netif_running(netdev)) netif_poll_disable(nic->netdev); -#endif del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index da459f7177c..fb96c87f9e5 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -100,6 +100,9 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, { "rx_header_split", E1000_STAT(rx_hdr_split) }, { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, + { "tx_smbus", E1000_STAT(stats.mgptc) }, + { "rx_smbus", E1000_STAT(stats.mgprc) }, + { "dropped_smbus", E1000_STAT(stats.mgpdc) }, }; #define E1000_QUEUE_STATS_LEN 0 diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 3655d902b0b..9be44699300 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -308,141 +308,160 @@ e1000_phy_init_script(struct e1000_hw *hw) int32_t e1000_set_mac_type(struct e1000_hw *hw) { - DEBUGFUNC("e1000_set_mac_type"); - - switch (hw->device_id) { - case E1000_DEV_ID_82542: - switch (hw->revision_id) { - case E1000_82542_2_0_REV_ID: - hw->mac_type = e1000_82542_rev2_0; - break; - case E1000_82542_2_1_REV_ID: - hw->mac_type = e1000_82542_rev2_1; - break; - default: - /* Invalid 82542 revision ID */ - return -E1000_ERR_MAC_TYPE; - } - break; - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - hw->mac_type = e1000_82543; - break; - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: - hw->mac_type = e1000_82544; - break; - case E1000_DEV_ID_82540EM: - case E1000_DEV_ID_82540EM_LOM: - case E1000_DEV_ID_82540EP: - case E1000_DEV_ID_82540EP_LOM: - case E1000_DEV_ID_82540EP_LP: - hw->mac_type = e1000_82540; - break; - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82545EM_FIBER: - hw->mac_type = e1000_82545; - break; - case E1000_DEV_ID_82545GM_COPPER: - case E1000_DEV_ID_82545GM_FIBER: - case E1000_DEV_ID_82545GM_SERDES: - hw->mac_type = e1000_82545_rev_3; - break; - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_FIBER: - case E1000_DEV_ID_82546EB_QUAD_COPPER: - hw->mac_type = e1000_82546; - break; - case E1000_DEV_ID_82546GB_COPPER: - case E1000_DEV_ID_82546GB_FIBER: - case E1000_DEV_ID_82546GB_SERDES: - case E1000_DEV_ID_82546GB_PCIE: - case E1000_DEV_ID_82546GB_QUAD_COPPER: - case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: - hw->mac_type = e1000_82546_rev_3; - break; - case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EI_MOBILE: - case E1000_DEV_ID_82541ER_LOM: - hw->mac_type = e1000_82541; - break; - case E1000_DEV_ID_82541ER: - case E1000_DEV_ID_82541GI: - case E1000_DEV_ID_82541GI_LF: - case E1000_DEV_ID_82541GI_MOBILE: - hw->mac_type = e1000_82541_rev_2; - break; - case E1000_DEV_ID_82547EI: - case E1000_DEV_ID_82547EI_MOBILE: - hw->mac_type = e1000_82547; - break; - case E1000_DEV_ID_82547GI: - hw->mac_type = e1000_82547_rev_2; - break; - case E1000_DEV_ID_82571EB_COPPER: - case E1000_DEV_ID_82571EB_FIBER: - case E1000_DEV_ID_82571EB_SERDES: - case E1000_DEV_ID_82571EB_QUAD_COPPER: - case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: - hw->mac_type = e1000_82571; - break; - case E1000_DEV_ID_82572EI_COPPER: - case E1000_DEV_ID_82572EI_FIBER: - case E1000_DEV_ID_82572EI_SERDES: - case E1000_DEV_ID_82572EI: - hw->mac_type = e1000_82572; - break; - case E1000_DEV_ID_82573E: - case E1000_DEV_ID_82573E_IAMT: - case E1000_DEV_ID_82573L: - hw->mac_type = e1000_82573; - break; - case E1000_DEV_ID_80003ES2LAN_COPPER_SPT: - case E1000_DEV_ID_80003ES2LAN_SERDES_SPT: - case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: - case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: - hw->mac_type = e1000_80003es2lan; - break; - case E1000_DEV_ID_ICH8_IGP_M_AMT: - case E1000_DEV_ID_ICH8_IGP_AMT: - case E1000_DEV_ID_ICH8_IGP_C: - case E1000_DEV_ID_ICH8_IFE: - case E1000_DEV_ID_ICH8_IFE_GT: - case E1000_DEV_ID_ICH8_IFE_G: - case E1000_DEV_ID_ICH8_IGP_M: - hw->mac_type = e1000_ich8lan; - break; - default: - /* Should never have loaded on this device */ - return -E1000_ERR_MAC_TYPE; - } - - switch (hw->mac_type) { - case e1000_ich8lan: - hw->swfwhw_semaphore_present = TRUE; - hw->asf_firmware_present = TRUE; - break; - case e1000_80003es2lan: - hw->swfw_sync_present = TRUE; - /* fall through */ - case e1000_82571: - case e1000_82572: - case e1000_82573: - hw->eeprom_semaphore_present = TRUE; - /* fall through */ - case e1000_82541: - case e1000_82547: - case e1000_82541_rev_2: - case e1000_82547_rev_2: - hw->asf_firmware_present = TRUE; - break; - default: - break; - } - - return E1000_SUCCESS; + DEBUGFUNC("e1000_set_mac_type"); + + switch (hw->device_id) { + case E1000_DEV_ID_82542: + switch (hw->revision_id) { + case E1000_82542_2_0_REV_ID: + hw->mac_type = e1000_82542_rev2_0; + break; + case E1000_82542_2_1_REV_ID: + hw->mac_type = e1000_82542_rev2_1; + break; + default: + /* Invalid 82542 revision ID */ + return -E1000_ERR_MAC_TYPE; + } + break; + case E1000_DEV_ID_82543GC_FIBER: + case E1000_DEV_ID_82543GC_COPPER: + hw->mac_type = e1000_82543; + break; + case E1000_DEV_ID_82544EI_COPPER: + case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82544GC_COPPER: + case E1000_DEV_ID_82544GC_LOM: + hw->mac_type = e1000_82544; + break; + case E1000_DEV_ID_82540EM: + case E1000_DEV_ID_82540EM_LOM: + case E1000_DEV_ID_82540EP: + case E1000_DEV_ID_82540EP_LOM: + case E1000_DEV_ID_82540EP_LP: + hw->mac_type = e1000_82540; + break; + case E1000_DEV_ID_82545EM_COPPER: + case E1000_DEV_ID_82545EM_FIBER: + hw->mac_type = e1000_82545; + break; + case E1000_DEV_ID_82545GM_COPPER: + case E1000_DEV_ID_82545GM_FIBER: + case E1000_DEV_ID_82545GM_SERDES: + hw->mac_type = e1000_82545_rev_3; + break; + case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: + hw->mac_type = e1000_82546; + break; + case E1000_DEV_ID_82546GB_COPPER: + case E1000_DEV_ID_82546GB_FIBER: + case E1000_DEV_ID_82546GB_SERDES: + case E1000_DEV_ID_82546GB_PCIE: + case E1000_DEV_ID_82546GB_QUAD_COPPER: + case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: + hw->mac_type = e1000_82546_rev_3; + break; + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EI_MOBILE: + case E1000_DEV_ID_82541ER_LOM: + hw->mac_type = e1000_82541; + break; + case E1000_DEV_ID_82541ER: + case E1000_DEV_ID_82541GI: + case E1000_DEV_ID_82541GI_LF: + case E1000_DEV_ID_82541GI_MOBILE: + hw->mac_type = e1000_82541_rev_2; + break; + case E1000_DEV_ID_82547EI: + case E1000_DEV_ID_82547EI_MOBILE: + hw->mac_type = e1000_82547; + break; + case E1000_DEV_ID_82547GI: + hw->mac_type = e1000_82547_rev_2; + break; + case E1000_DEV_ID_82571EB_COPPER: + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: + hw->mac_type = e1000_82571; + break; + case E1000_DEV_ID_82572EI_COPPER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_82572EI: + hw->mac_type = e1000_82572; + break; + case E1000_DEV_ID_82573E: + case E1000_DEV_ID_82573E_IAMT: + case E1000_DEV_ID_82573L: + hw->mac_type = e1000_82573; + break; + case E1000_DEV_ID_80003ES2LAN_COPPER_SPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_SPT: + case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->mac_type = e1000_80003es2lan; + break; + case E1000_DEV_ID_ICH8_IGP_M_AMT: + case E1000_DEV_ID_ICH8_IGP_AMT: + case E1000_DEV_ID_ICH8_IGP_C: + case E1000_DEV_ID_ICH8_IFE: + case E1000_DEV_ID_ICH8_IFE_GT: + case E1000_DEV_ID_ICH8_IFE_G: + case E1000_DEV_ID_ICH8_IGP_M: + hw->mac_type = e1000_ich8lan; + break; + default: + /* Should never have loaded on this device */ + return -E1000_ERR_MAC_TYPE; + } + + switch (hw->mac_type) { + case e1000_ich8lan: + hw->swfwhw_semaphore_present = TRUE; + hw->asf_firmware_present = TRUE; + break; + case e1000_80003es2lan: + hw->swfw_sync_present = TRUE; + /* fall through */ + case e1000_82571: + case e1000_82572: + case e1000_82573: + hw->eeprom_semaphore_present = TRUE; + /* fall through */ + case e1000_82541: + case e1000_82547: + case e1000_82541_rev_2: + case e1000_82547_rev_2: + hw->asf_firmware_present = TRUE; + break; + default: + break; + } + + /* The 82543 chip does not count tx_carrier_errors properly in + * FD mode + */ + if (hw->mac_type == e1000_82543) + hw->bad_tx_carr_stats_fd = TRUE; + + /* capable of receiving management packets to the host */ + if (hw->mac_type >= e1000_82571) + hw->has_manc2h = TRUE; + + /* In rare occasions, ESB2 systems would end up started without + * the RX unit being turned on. + */ + if (hw->mac_type == e1000_80003es2lan) + hw->rx_needs_kicking = TRUE; + + if (hw->mac_type > e1000_82544) + hw->has_smbus = TRUE; + + return E1000_SUCCESS; } /***************************************************************************** @@ -6575,7 +6594,7 @@ e1000_get_bus_info(struct e1000_hw *hw) switch (hw->mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: - hw->bus_type = e1000_bus_type_unknown; + hw->bus_type = e1000_bus_type_pci; hw->bus_speed = e1000_bus_speed_unknown; hw->bus_width = e1000_bus_width_unknown; break; @@ -7817,9 +7836,8 @@ e1000_enable_mng_pass_thru(struct e1000_hw *hw) fwsm = E1000_READ_REG(hw, FWSM); factps = E1000_READ_REG(hw, FACTPS); - if (((fwsm & E1000_FWSM_MODE_MASK) == - (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) && - (factps & E1000_FACTPS_MNGCG)) + if ((((fwsm & E1000_FWSM_MODE_MASK) >> E1000_FWSM_MODE_SHIFT) == + e1000_mng_mode_pt) && !(factps & E1000_FACTPS_MNGCG)) return TRUE; } else if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN)) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 3321fb13bfa..d6710588334 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1301,165 +1301,170 @@ struct e1000_ffvt_entry { #define E1000_82542_RSSIR E1000_RSSIR #define E1000_82542_KUMCTRLSTA E1000_KUMCTRLSTA #define E1000_82542_SW_FW_SYNC E1000_SW_FW_SYNC +#define E1000_82542_MANC2H E1000_MANC2H /* Statistics counters collected by the MAC */ struct e1000_hw_stats { - uint64_t crcerrs; - uint64_t algnerrc; - uint64_t symerrs; - uint64_t rxerrc; - uint64_t txerrc; - uint64_t mpc; - uint64_t scc; - uint64_t ecol; - uint64_t mcc; - uint64_t latecol; - uint64_t colc; - uint64_t dc; - uint64_t tncrs; - uint64_t sec; - uint64_t cexterr; - uint64_t rlec; - uint64_t xonrxc; - uint64_t xontxc; - uint64_t xoffrxc; - uint64_t xofftxc; - uint64_t fcruc; - uint64_t prc64; - uint64_t prc127; - uint64_t prc255; - uint64_t prc511; - uint64_t prc1023; - uint64_t prc1522; - uint64_t gprc; - uint64_t bprc; - uint64_t mprc; - uint64_t gptc; - uint64_t gorcl; - uint64_t gorch; - uint64_t gotcl; - uint64_t gotch; - uint64_t rnbc; - uint64_t ruc; - uint64_t rfc; - uint64_t roc; - uint64_t rlerrc; - uint64_t rjc; - uint64_t mgprc; - uint64_t mgpdc; - uint64_t mgptc; - uint64_t torl; - uint64_t torh; - uint64_t totl; - uint64_t toth; - uint64_t tpr; - uint64_t tpt; - uint64_t ptc64; - uint64_t ptc127; - uint64_t ptc255; - uint64_t ptc511; - uint64_t ptc1023; - uint64_t ptc1522; - uint64_t mptc; - uint64_t bptc; - uint64_t tsctc; - uint64_t tsctfc; - uint64_t iac; - uint64_t icrxptc; - uint64_t icrxatc; - uint64_t ictxptc; - uint64_t ictxatc; - uint64_t ictxqec; - uint64_t ictxqmtc; - uint64_t icrxdmtc; - uint64_t icrxoc; + uint64_t crcerrs; + uint64_t algnerrc; + uint64_t symerrs; + uint64_t rxerrc; + uint64_t txerrc; + uint64_t mpc; + uint64_t scc; + uint64_t ecol; + uint64_t mcc; + uint64_t latecol; + uint64_t colc; + uint64_t dc; + uint64_t tncrs; + uint64_t sec; + uint64_t cexterr; + uint64_t rlec; + uint64_t xonrxc; + uint64_t xontxc; + uint64_t xoffrxc; + uint64_t xofftxc; + uint64_t fcruc; + uint64_t prc64; + uint64_t prc127; + uint64_t prc255; + uint64_t prc511; + uint64_t prc1023; + uint64_t prc1522; + uint64_t gprc; + uint64_t bprc; + uint64_t mprc; + uint64_t gptc; + uint64_t gorcl; + uint64_t gorch; + uint64_t gotcl; + uint64_t gotch; + uint64_t rnbc; + uint64_t ruc; + uint64_t rfc; + uint64_t roc; + uint64_t rlerrc; + uint64_t rjc; + uint64_t mgprc; + uint64_t mgpdc; + uint64_t mgptc; + uint64_t torl; + uint64_t torh; + uint64_t totl; + uint64_t toth; + uint64_t tpr; + uint64_t tpt; + uint64_t ptc64; + uint64_t ptc127; + uint64_t ptc255; + uint64_t ptc511; + uint64_t ptc1023; + uint64_t ptc1522; + uint64_t mptc; + uint64_t bptc; + uint64_t tsctc; + uint64_t tsctfc; + uint64_t iac; + uint64_t icrxptc; + uint64_t icrxatc; + uint64_t ictxptc; + uint64_t ictxatc; + uint64_t ictxqec; + uint64_t ictxqmtc; + uint64_t icrxdmtc; + uint64_t icrxoc; }; /* Structure containing variables used by the shared code (e1000_hw.c) */ struct e1000_hw { - uint8_t __iomem *hw_addr; - uint8_t __iomem *flash_address; - e1000_mac_type mac_type; - e1000_phy_type phy_type; - uint32_t phy_init_script; - e1000_media_type media_type; - void *back; - struct e1000_shadow_ram *eeprom_shadow_ram; - uint32_t flash_bank_size; - uint32_t flash_base_addr; - e1000_fc_type fc; - e1000_bus_speed bus_speed; - e1000_bus_width bus_width; - e1000_bus_type bus_type; - struct e1000_eeprom_info eeprom; - e1000_ms_type master_slave; - e1000_ms_type original_master_slave; - e1000_ffe_config ffe_config_state; - uint32_t asf_firmware_present; - uint32_t eeprom_semaphore_present; - uint32_t swfw_sync_present; - uint32_t swfwhw_semaphore_present; - unsigned long io_base; - uint32_t phy_id; - uint32_t phy_revision; - uint32_t phy_addr; - uint32_t original_fc; - uint32_t txcw; - uint32_t autoneg_failed; - uint32_t max_frame_size; - uint32_t min_frame_size; - uint32_t mc_filter_type; - uint32_t num_mc_addrs; - uint32_t collision_delta; - uint32_t tx_packet_delta; - uint32_t ledctl_default; - uint32_t ledctl_mode1; - uint32_t ledctl_mode2; - boolean_t tx_pkt_filtering; - struct e1000_host_mng_dhcp_cookie mng_cookie; - uint16_t phy_spd_default; - uint16_t autoneg_advertised; - uint16_t pci_cmd_word; - uint16_t fc_high_water; - uint16_t fc_low_water; - uint16_t fc_pause_time; - uint16_t current_ifs_val; - uint16_t ifs_min_val; - uint16_t ifs_max_val; - uint16_t ifs_step_size; - uint16_t ifs_ratio; - uint16_t device_id; - uint16_t vendor_id; - uint16_t subsystem_id; - uint16_t subsystem_vendor_id; - uint8_t revision_id; - uint8_t autoneg; - uint8_t mdix; - uint8_t forced_speed_duplex; - uint8_t wait_autoneg_complete; - uint8_t dma_fairness; - uint8_t mac_addr[NODE_ADDRESS_SIZE]; - uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; - boolean_t disable_polarity_correction; - boolean_t speed_downgraded; - e1000_smart_speed smart_speed; - e1000_dsp_config dsp_config_state; - boolean_t get_link_status; - boolean_t serdes_link_down; - boolean_t tbi_compatibility_en; - boolean_t tbi_compatibility_on; - boolean_t laa_is_present; - boolean_t phy_reset_disable; - boolean_t initialize_hw_bits_disable; - boolean_t fc_send_xon; - boolean_t fc_strict_ieee; - boolean_t report_tx_early; - boolean_t adaptive_ifs; - boolean_t ifs_params_forced; - boolean_t in_ifs_mode; - boolean_t mng_reg_access_disabled; - boolean_t leave_av_bit_off; - boolean_t kmrn_lock_loss_workaround_disabled; + uint8_t __iomem *hw_addr; + uint8_t __iomem *flash_address; + e1000_mac_type mac_type; + e1000_phy_type phy_type; + uint32_t phy_init_script; + e1000_media_type media_type; + void *back; + struct e1000_shadow_ram *eeprom_shadow_ram; + uint32_t flash_bank_size; + uint32_t flash_base_addr; + e1000_fc_type fc; + e1000_bus_speed bus_speed; + e1000_bus_width bus_width; + e1000_bus_type bus_type; + struct e1000_eeprom_info eeprom; + e1000_ms_type master_slave; + e1000_ms_type original_master_slave; + e1000_ffe_config ffe_config_state; + uint32_t asf_firmware_present; + uint32_t eeprom_semaphore_present; + uint32_t swfw_sync_present; + uint32_t swfwhw_semaphore_present; + unsigned long io_base; + uint32_t phy_id; + uint32_t phy_revision; + uint32_t phy_addr; + uint32_t original_fc; + uint32_t txcw; + uint32_t autoneg_failed; + uint32_t max_frame_size; + uint32_t min_frame_size; + uint32_t mc_filter_type; + uint32_t num_mc_addrs; + uint32_t collision_delta; + uint32_t tx_packet_delta; + uint32_t ledctl_default; + uint32_t ledctl_mode1; + uint32_t ledctl_mode2; + boolean_t tx_pkt_filtering; + struct e1000_host_mng_dhcp_cookie mng_cookie; + uint16_t phy_spd_default; + uint16_t autoneg_advertised; + uint16_t pci_cmd_word; + uint16_t fc_high_water; + uint16_t fc_low_water; + uint16_t fc_pause_time; + uint16_t current_ifs_val; + uint16_t ifs_min_val; + uint16_t ifs_max_val; + uint16_t ifs_step_size; + uint16_t ifs_ratio; + uint16_t device_id; + uint16_t vendor_id; + uint16_t subsystem_id; + uint16_t subsystem_vendor_id; + uint8_t revision_id; + uint8_t autoneg; + uint8_t mdix; + uint8_t forced_speed_duplex; + uint8_t wait_autoneg_complete; + uint8_t dma_fairness; + uint8_t mac_addr[NODE_ADDRESS_SIZE]; + uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; + boolean_t disable_polarity_correction; + boolean_t speed_downgraded; + e1000_smart_speed smart_speed; + e1000_dsp_config dsp_config_state; + boolean_t get_link_status; + boolean_t serdes_link_down; + boolean_t tbi_compatibility_en; + boolean_t tbi_compatibility_on; + boolean_t laa_is_present; + boolean_t phy_reset_disable; + boolean_t initialize_hw_bits_disable; + boolean_t fc_send_xon; + boolean_t fc_strict_ieee; + boolean_t report_tx_early; + boolean_t adaptive_ifs; + boolean_t ifs_params_forced; + boolean_t in_ifs_mode; + boolean_t mng_reg_access_disabled; + boolean_t leave_av_bit_off; + boolean_t kmrn_lock_loss_workaround_disabled; + boolean_t bad_tx_carr_stats_fd; + boolean_t has_manc2h; + boolean_t rx_needs_kicking; + boolean_t has_smbus; }; @@ -2418,6 +2423,7 @@ struct e1000_host_command_info { #define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ #define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */ #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_20K 0x0014 #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 #define E1000_PBA_30K 0x001E diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 73f3a85fd23..c6259c7127f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -213,6 +213,12 @@ static void e1000_netpoll (struct net_device *netdev); extern void e1000_check_options(struct e1000_adapter *adapter); +#define COPYBREAK_DEFAULT 256 +static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT; +module_param(copybreak, uint, 0644); +MODULE_PARM_DESC(copybreak, + "Maximum size of packet that is copied to a new buffer on receive"); + static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state); static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev); @@ -264,7 +270,13 @@ e1000_init_module(void) printk(KERN_INFO "%s\n", e1000_copyright); ret = pci_register_driver(&e1000_driver); - + if (copybreak != COPYBREAK_DEFAULT) { + if (copybreak == 0) + printk(KERN_INFO "e1000: copybreak disabled\n"); + else + printk(KERN_INFO "e1000: copybreak enabled for " + "packets <= %u bytes\n", copybreak); + } return ret; } @@ -464,6 +476,52 @@ e1000_get_hw_control(struct e1000_adapter *adapter) } } +static void +e1000_init_manageability(struct e1000_adapter *adapter) +{ + if (adapter->en_mng_pt) { + uint32_t manc = E1000_READ_REG(&adapter->hw, MANC); + + /* disable hardware interception of ARP */ + manc &= ~(E1000_MANC_ARP_EN); + + /* enable receiving management packets to the host */ + /* this will probably generate destination unreachable messages + * from the host OS, but the packets will be handled on SMBUS */ + if (adapter->hw.has_manc2h) { + uint32_t manc2h = E1000_READ_REG(&adapter->hw, MANC2H); + + manc |= E1000_MANC_EN_MNG2HOST; +#define E1000_MNG2HOST_PORT_623 (1 << 5) +#define E1000_MNG2HOST_PORT_664 (1 << 6) + manc2h |= E1000_MNG2HOST_PORT_623; + manc2h |= E1000_MNG2HOST_PORT_664; + E1000_WRITE_REG(&adapter->hw, MANC2H, manc2h); + } + + E1000_WRITE_REG(&adapter->hw, MANC, manc); + } +} + +static void +e1000_release_manageability(struct e1000_adapter *adapter) +{ + if (adapter->en_mng_pt) { + uint32_t manc = E1000_READ_REG(&adapter->hw, MANC); + + /* re-enable hardware interception of ARP */ + manc |= E1000_MANC_ARP_EN; + + if (adapter->hw.has_manc2h) + manc &= ~E1000_MANC_EN_MNG2HOST; + + /* don't explicitly have to mess with MANC2H since + * MANC has an enable disable that gates MANC2H */ + + E1000_WRITE_REG(&adapter->hw, MANC, manc); + } +} + int e1000_up(struct e1000_adapter *adapter) { @@ -475,6 +533,7 @@ e1000_up(struct e1000_adapter *adapter) e1000_set_multi(netdev); e1000_restore_vlan(adapter); + e1000_init_manageability(adapter); e1000_configure_tx(adapter); e1000_setup_rctl(adapter); @@ -497,7 +556,8 @@ e1000_up(struct e1000_adapter *adapter) clear_bit(__E1000_DOWN, &adapter->flags); - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); + /* fire a link change interrupt to start the watchdog */ + E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC); return 0; } @@ -614,16 +674,34 @@ e1000_reinit_locked(struct e1000_adapter *adapter) void e1000_reset(struct e1000_adapter *adapter) { - uint32_t pba, manc; + uint32_t pba = 0, tx_space, min_tx_space, min_rx_space; uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF; + boolean_t legacy_pba_adjust = FALSE; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. */ switch (adapter->hw.mac_type) { + case e1000_82542_rev2_0: + case e1000_82542_rev2_1: + case e1000_82543: + case e1000_82544: + case e1000_82540: + case e1000_82541: + case e1000_82541_rev_2: + legacy_pba_adjust = TRUE; + pba = E1000_PBA_48K; + break; + case e1000_82545: + case e1000_82545_rev_3: + case e1000_82546: + case e1000_82546_rev_3: + pba = E1000_PBA_48K; + break; case e1000_82547: case e1000_82547_rev_2: + legacy_pba_adjust = TRUE; pba = E1000_PBA_30K; break; case e1000_82571: @@ -632,27 +710,80 @@ e1000_reset(struct e1000_adapter *adapter) pba = E1000_PBA_38K; break; case e1000_82573: - pba = E1000_PBA_12K; + pba = E1000_PBA_20K; break; case e1000_ich8lan: pba = E1000_PBA_8K; - break; - default: - pba = E1000_PBA_48K; + case e1000_undefined: + case e1000_num_macs: break; } - if ((adapter->hw.mac_type != e1000_82573) && - (adapter->netdev->mtu > E1000_RXBUFFER_8192)) - pba -= 8; /* allocate more FIFO for Tx */ + if (legacy_pba_adjust == TRUE) { + if (adapter->netdev->mtu > E1000_RXBUFFER_8192) + pba -= 8; /* allocate more FIFO for Tx */ + if (adapter->hw.mac_type == e1000_82547) { + adapter->tx_fifo_head = 0; + adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; + adapter->tx_fifo_size = + (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; + atomic_set(&adapter->tx_fifo_stall, 0); + } + } else if (adapter->hw.max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) { + /* adjust PBA for jumbo frames */ + E1000_WRITE_REG(&adapter->hw, PBA, pba); + + /* To maintain wire speed transmits, the Tx FIFO should be + * large enough to accomodate two full transmit packets, + * rounded up to the next 1KB and expressed in KB. Likewise, + * the Rx FIFO should be large enough to accomodate at least + * one full receive packet and is similarly rounded up and + * expressed in KB. */ + pba = E1000_READ_REG(&adapter->hw, PBA); + /* upper 16 bits has Tx packet buffer allocation size in KB */ + tx_space = pba >> 16; + /* lower 16 bits has Rx packet buffer allocation size in KB */ + pba &= 0xffff; + /* don't include ethernet FCS because hardware appends/strips */ + min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE + + VLAN_TAG_SIZE; + min_tx_space = min_rx_space; + min_tx_space *= 2; + E1000_ROUNDUP(min_tx_space, 1024); + min_tx_space >>= 10; + E1000_ROUNDUP(min_rx_space, 1024); + min_rx_space >>= 10; + + /* If current Tx allocation is less than the min Tx FIFO size, + * and the min Tx FIFO size is less than the current Rx FIFO + * allocation, take space away from current Rx allocation */ + if (tx_space < min_tx_space && + ((min_tx_space - tx_space) < pba)) { + pba = pba - (min_tx_space - tx_space); + + /* PCI/PCIx hardware has PBA alignment constraints */ + switch (adapter->hw.mac_type) { + case e1000_82545 ... e1000_82546_rev_3: + pba &= ~(E1000_PBA_8K - 1); + break; + default: + break; + } - if (adapter->hw.mac_type == e1000_82547) { - adapter->tx_fifo_head = 0; - adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; - adapter->tx_fifo_size = - (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; - atomic_set(&adapter->tx_fifo_stall, 0); + /* if short on rx space, rx wins and must trump tx + * adjustment or use Early Receive if available */ + if (pba < min_rx_space) { + switch (adapter->hw.mac_type) { + case e1000_82573: + /* ERT enabled in e1000_configure_rx */ + break; + default: + pba = min_rx_space; + break; + } + } + } } E1000_WRITE_REG(&adapter->hw, PBA, pba); @@ -685,6 +816,20 @@ e1000_reset(struct e1000_adapter *adapter) if (e1000_init_hw(&adapter->hw)) DPRINTK(PROBE, ERR, "Hardware Error\n"); e1000_update_mng_vlan(adapter); + + /* if (adapter->hwflags & HWFLAGS_PHY_PWR_BIT) { */ + if (adapter->hw.mac_type >= e1000_82544 && + adapter->hw.mac_type <= e1000_82547_rev_2 && + adapter->hw.autoneg == 1 && + adapter->hw.autoneg_advertised == ADVERTISE_1000_FULL) { + uint32_t ctrl = E1000_READ_REG(&adapter->hw, CTRL); + /* clear phy power management bit if we are in gig only mode, + * which if enabled will attempt negotiation to 100Mb, which + * can cause a loss of link at power off or driver unload */ + ctrl &= ~E1000_CTRL_SWDPIN3; + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); + } + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); @@ -705,14 +850,7 @@ e1000_reset(struct e1000_adapter *adapter) phy_data); } - if ((adapter->en_mng_pt) && - (adapter->hw.mac_type >= e1000_82540) && - (adapter->hw.mac_type < e1000_82571) && - (adapter->hw.media_type == e1000_media_type_copper)) { - manc = E1000_READ_REG(&adapter->hw, MANC); - manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); - E1000_WRITE_REG(&adapter->hw, MANC, manc); - } + e1000_release_manageability(adapter); } /** @@ -1078,22 +1216,13 @@ e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - uint32_t manc; #ifdef CONFIG_E1000_NAPI int i; #endif flush_scheduled_work(); - if (adapter->hw.mac_type >= e1000_82540 && - adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { - manc = E1000_READ_REG(&adapter->hw, MANC); - if (manc & E1000_MANC_SMBUS_EN) { - manc |= E1000_MANC_ARP_EN; - E1000_WRITE_REG(&adapter->hw, MANC, manc); - } - } + e1000_release_manageability(adapter); /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ @@ -1531,9 +1660,9 @@ e1000_configure_tx(struct e1000_adapter *adapter) } /* Set the default values for the Tx Inter Packet Gap timer */ - - if (hw->media_type == e1000_media_type_fiber || - hw->media_type == e1000_media_type_internal_serdes) + if (adapter->hw.mac_type <= e1000_82547_rev_2 && + (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes)) tipg = DEFAULT_82543_TIPG_IPGT_FIBER; else tipg = DEFAULT_82543_TIPG_IPGT_COPPER; @@ -2528,6 +2657,13 @@ e1000_watchdog(unsigned long data) netif_wake_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); adapter->smartspeed = 0; + } else { + /* make sure the receive unit is started */ + if (adapter->hw.rx_needs_kicking) { + struct e1000_hw *hw = &adapter->hw; + uint32_t rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl | E1000_RCTL_EN); + } } } else { if (netif_carrier_ok(netdev)) { @@ -2628,29 +2764,34 @@ static unsigned int e1000_update_itr(struct e1000_adapter *adapter, if (packets == 0) goto update_itr_done; - switch (itr_setting) { case lowest_latency: - if ((packets < 5) && (bytes > 512)) + /* jumbo frames get bulk treatment*/ + if (bytes/packets > 8000) + retval = bulk_latency; + else if ((packets < 5) && (bytes > 512)) retval = low_latency; break; case low_latency: /* 50 usec aka 20000 ints/s */ if (bytes > 10000) { - if ((packets < 10) || - ((bytes/packets) > 1200)) + /* jumbo frames need bulk latency setting */ + if (bytes/packets > 8000) + retval = bulk_latency; + else if ((packets < 10) || ((bytes/packets) > 1200)) retval = bulk_latency; else if ((packets > 35)) retval = lowest_latency; - } else if (packets <= 2 && bytes < 512) + } else if (bytes/packets > 2000) + retval = bulk_latency; + else if (packets <= 2 && bytes < 512) retval = lowest_latency; break; case bulk_latency: /* 250 usec aka 4000 ints/s */ if (bytes > 25000) { if (packets > 35) retval = low_latency; - } else { - if (bytes < 6000) - retval = low_latency; + } else if (bytes < 6000) { + retval = low_latency; } break; } @@ -2679,17 +2820,20 @@ static void e1000_set_itr(struct e1000_adapter *adapter) adapter->tx_itr, adapter->total_tx_packets, adapter->total_tx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency) + adapter->tx_itr = low_latency; + adapter->rx_itr = e1000_update_itr(adapter, adapter->rx_itr, adapter->total_rx_packets, adapter->total_rx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) + adapter->rx_itr = low_latency; current_itr = max(adapter->rx_itr, adapter->tx_itr); - /* conservative mode eliminates the lowest_latency setting */ - if (current_itr == lowest_latency && (adapter->itr_setting == 3)) - current_itr = low_latency; - switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ case lowest_latency: @@ -3168,6 +3312,16 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { switch (adapter->hw.mac_type) { unsigned int pull_size; + case e1000_82544: + /* Make sure we have room to chop off 4 bytes, + * and that the end alignment will work out to + * this hardware's requirements + * NOTE: this is a TSO only workaround + * if end byte alignment not correct move us + * into the next dword */ + if ((unsigned long)(skb->tail - 1) & 4) + break; + /* fall through */ case e1000_82571: case e1000_82572: case e1000_82573: @@ -3419,12 +3573,11 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; netdev->mtu = new_mtu; + adapter->hw.max_frame_size = max_frame; if (netif_running(netdev)) e1000_reinit_locked(adapter); - adapter->hw.max_frame_size = max_frame; - return 0; } @@ -3573,6 +3726,11 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; adapter->net_stats.tx_window_errors = adapter->stats.latecol; adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; + if (adapter->hw.bad_tx_carr_stats_fd && + adapter->link_duplex == FULL_DUPLEX) { + adapter->net_stats.tx_carrier_errors = 0; + adapter->stats.tncrs = 0; + } /* Tx Dropped needs to be maintained elsewhere */ @@ -3590,6 +3748,13 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->phy_stats.receive_errors += phy_tmp; } + /* Management Stats */ + if (adapter->hw.has_smbus) { + adapter->stats.mgptc += E1000_READ_REG(hw, MGTPTC); + adapter->stats.mgprc += E1000_READ_REG(hw, MGTPRC); + adapter->stats.mgpdc += E1000_READ_REG(hw, MGTPDC); + } + spin_unlock_irqrestore(&adapter->stats_lock, flags); } #ifdef CONFIG_PCI_MSI @@ -3868,11 +4033,11 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, cleaned = (i == eop); if (cleaned) { - /* this packet count is wrong for TSO but has a - * tendency to make dynamic ITR change more - * towards bulk */ + struct sk_buff *skb = buffer_info->skb; + unsigned int segs = skb_shinfo(skb)->gso_segs; + total_tx_packets += segs; total_tx_packets++; - total_tx_bytes += buffer_info->skb->len; + total_tx_bytes += skb->len; } e1000_unmap_and_free_tx_resource(adapter, buffer_info); tx_desc->upper.data = 0; @@ -4094,8 +4259,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, /* code added for copybreak, this should improve * performance for small packets with large amounts * of reassembly being done in the stack */ -#define E1000_CB_LENGTH 256 - if (length < E1000_CB_LENGTH) { + if (length < copybreak) { struct sk_buff *new_skb = netdev_alloc_skb(netdev, length + NET_IP_ALIGN); if (new_skb) { @@ -4253,7 +4417,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, /* page alloc/put takes too long and effects small packet * throughput, so unsplit small packets and save the alloc/put*/ - if (l1 && ((length + l1) <= adapter->rx_ps_bsize0)) { + if (l1 && (l1 <= copybreak) && ((length + l1) <= adapter->rx_ps_bsize0)) { u8 *vaddr; /* there is no documentation about how to call * kmap_atomic, so we can't hold the mapping @@ -4998,7 +5162,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - uint32_t ctrl, ctrl_ext, rctl, manc, status; + uint32_t ctrl, ctrl_ext, rctl, status; uint32_t wufc = adapter->wol; #ifdef CONFIG_PM int retval = 0; @@ -5067,16 +5231,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } - if (adapter->hw.mac_type >= e1000_82540 && - adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { - manc = E1000_READ_REG(&adapter->hw, MANC); - if (manc & E1000_MANC_SMBUS_EN) { - manc |= E1000_MANC_ARP_EN; - E1000_WRITE_REG(&adapter->hw, MANC, manc); - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } + e1000_release_manageability(adapter); + + /* make sure adapter isn't asleep if manageability is enabled */ + if (adapter->en_mng_pt) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); } if (adapter->hw.phy_type == e1000_phy_igp_3) @@ -5102,7 +5262,7 @@ e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - uint32_t manc, err; + uint32_t err; pci_set_power_state(pdev, PCI_D0); e1000_pci_restore_state(adapter); @@ -5122,19 +5282,13 @@ e1000_resume(struct pci_dev *pdev) e1000_reset(adapter); E1000_WRITE_REG(&adapter->hw, WUS, ~0); + e1000_init_manageability(adapter); + if (netif_running(netdev)) e1000_up(adapter); netif_device_attach(netdev); - if (adapter->hw.mac_type >= e1000_82540 && - adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { - manc = E1000_READ_REG(&adapter->hw, MANC); - manc &= ~(E1000_MANC_ARP_EN); - E1000_WRITE_REG(&adapter->hw, MANC, manc); - } - /* If the controller is 82573 and f/w is AMT, do not set * DRV_LOAD until the interface is up. For all other cases, * let the f/w know that the h/w is now under the control @@ -5235,7 +5389,8 @@ static void e1000_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev->priv; - uint32_t manc, swsm; + + e1000_init_manageability(adapter); if (netif_running(netdev)) { if (e1000_up(adapter)) { @@ -5246,26 +5401,14 @@ static void e1000_io_resume(struct pci_dev *pdev) netif_device_attach(netdev); - if (adapter->hw.mac_type >= e1000_82540 && - adapter->hw.mac_type < e1000_82571 && - adapter->hw.media_type == e1000_media_type_copper) { - manc = E1000_READ_REG(&adapter->hw, MANC); - manc &= ~(E1000_MANC_ARP_EN); - E1000_WRITE_REG(&adapter->hw, MANC, manc); - } - - switch (adapter->hw.mac_type) { - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm | E1000_SWSM_DRV_LOAD); - break; - default: - break; - } + /* If the controller is 82573 and f/w is AMT, do not set + * DRV_LOAD until the interface is up. For all other cases, + * let the f/w know that the h/w is now under the control + * of the driver. */ + if (adapter->hw.mac_type != e1000_82573 || + !e1000_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); - if (netif_running(netdev)) - mod_timer(&adapter->watchdog_timer, jiffies); } /* e1000_main.c */ diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index cbfcd7f2889..cf2a279307e 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -487,7 +487,9 @@ e1000_check_options(struct e1000_adapter *adapter) e1000_validate_option(&adapter->itr, &opt, adapter); /* save the setting, because the dynamic bits change itr */ - adapter->itr_setting = adapter->itr; + /* clear the lower two bits because they are + * used as control */ + adapter->itr_setting = adapter->itr & ~3; break; } } else { diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 39ad9f73d1e..272e1ec51aa 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0043" +#define DRV_VERSION "EHEA_0045" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 83fa32f7239..9de2d38a532 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -558,12 +558,12 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) u32 qp_token; eqe = ehea_poll_eq(port->qp_eq); - ehea_debug("eqe=%p", eqe); + while (eqe) { - ehea_debug("*eqe=%lx", *(u64*)eqe); - eqe = ehea_poll_eq(port->qp_eq); qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry); - ehea_debug("next eqe=%p", eqe); + ehea_error("QP aff_err: entry=0x%lx, token=0x%x", + eqe->entry, qp_token); + eqe = ehea_poll_eq(port->qp_eq); } return IRQ_HANDLED; @@ -575,8 +575,9 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, int i; for (i = 0; i < adapter->num_ports; i++) - if (adapter->port[i]->logical_port_id == logical_port) - return adapter->port[i]; + if (adapter->port[i]) + if (adapter->port[i]->logical_port_id == logical_port) + return adapter->port[i]; return NULL; } @@ -642,6 +643,8 @@ int ehea_sense_port_attr(struct ehea_port *port) break; } + port->autoneg = 1; + /* Number of default QPs */ port->num_def_qps = cb0->num_default_qps; @@ -728,10 +731,7 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed) } } else { if (hret == H_AUTHORITY) { - ehea_info("Hypervisor denied setting port speed. Either" - " this partition is not authorized to set " - "port speed or another partition has modified" - " port speed first."); + ehea_info("Hypervisor denied setting port speed"); ret = -EPERM; } else { ret = -EIO; @@ -998,7 +998,7 @@ static int ehea_configure_port(struct ehea_port *port) | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); for (i = 0; i < port->num_def_qps; i++) - cb0->default_qpn_arr[i] = port->port_res[i].qp->init_attr.qp_nr; + cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr; if (netif_msg_ifup(port)) ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); @@ -1485,11 +1485,12 @@ out: static void ehea_promiscuous_error(u64 hret, int enable) { - ehea_info("Hypervisor denied %sabling promiscuous mode.%s", - enable == 1 ? "en" : "dis", - hret != H_AUTHORITY ? "" : " Another partition owning a " - "logical port on the same physical port might have altered " - "promiscuous mode first."); + if (hret == H_AUTHORITY) + ehea_info("Hypervisor denied %sabling promiscuous mode", + enable == 1 ? "en" : "dis"); + else + ehea_error("failed %sabling promiscuous mode", + enable == 1 ? "en" : "dis"); } static void ehea_promiscuous(struct net_device *dev, int enable) @@ -2267,6 +2268,8 @@ static void ehea_tx_watchdog(struct net_device *dev) int ehea_sense_adapter_attr(struct ehea_adapter *adapter) { struct hcp_query_ehea *cb; + struct device_node *lhea_dn = NULL; + struct device_node *eth_dn = NULL; u64 hret; int ret; @@ -2283,7 +2286,18 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) goto out_herr; } - adapter->num_ports = cb->num_ports; + /* Determine the number of available logical ports + * by counting the child nodes of the lhea OFDT entry + */ + adapter->num_ports = 0; + lhea_dn = of_find_node_by_name(lhea_dn, "lhea"); + do { + eth_dn = of_get_next_child(lhea_dn, eth_dn); + if (eth_dn) + adapter->num_ports++; + } while ( eth_dn ); + of_node_put(lhea_dn); + adapter->max_mc_mac = cb->max_mc_mac - 1; ret = 0; @@ -2302,6 +2316,7 @@ static int ehea_setup_single_port(struct ehea_port *port, struct ehea_adapter *adapter = port->adapter; struct hcp_ehea_port_cb4 *cb4; u32 *dn_log_port_id; + int jumbo = 0; sema_init(&port->port_lock, 1); port->state = EHEA_PORT_DOWN; @@ -2334,8 +2349,6 @@ static int ehea_setup_single_port(struct ehea_port *port, INIT_LIST_HEAD(&port->mc_list->list); - ehea_set_portspeed(port, EHEA_SPEED_AUTONEG); - ret = ehea_sense_port_attr(port); if (ret) goto out; @@ -2345,13 +2358,25 @@ static int ehea_setup_single_port(struct ehea_port *port, if (!cb4) { ehea_error("no mem for cb4"); } else { - cb4->jumbo_frame = 1; - hret = ehea_h_modify_ehea_port(adapter->handle, - port->logical_port_id, - H_PORT_CB4, H_PORT_CB4_JUMBO, - cb4); - if (hret != H_SUCCESS) { - ehea_info("Jumbo frames not activated"); + hret = ehea_h_query_ehea_port(adapter->handle, + port->logical_port_id, + H_PORT_CB4, + H_PORT_CB4_JUMBO, cb4); + + if (hret == H_SUCCESS) { + if (cb4->jumbo_frame) + jumbo = 1; + else { + cb4->jumbo_frame = 1; + hret = ehea_h_modify_ehea_port(adapter->handle, + port-> + logical_port_id, + H_PORT_CB4, + H_PORT_CB4_JUMBO, + cb4); + if (hret == H_SUCCESS) + jumbo = 1; + } } kfree(cb4); } @@ -2390,6 +2415,9 @@ static int ehea_setup_single_port(struct ehea_port *port, goto out_free; } + ehea_info("%s: Jumbo frames are %sabled", dev->name, + jumbo == 1 ? "en" : "dis"); + port->netdev = dev; ret = 0; goto out; @@ -2471,14 +2499,16 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", NULL); - if (!adapter_handle) { + if (adapter_handle) + adapter->handle = *adapter_handle; + + if (!adapter->handle) { dev_err(&dev->ofdev.dev, "failed getting handle for adapter" " '%s'\n", dev->ofdev.node->full_name); ret = -ENODEV; goto out_free_ad; } - adapter->handle = *adapter_handle; adapter->pd = EHEA_PD_ID; dev->ofdev.dev.driver_data = adapter; @@ -2568,6 +2598,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev) destroy_workqueue(adapter->ehea_wq); ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); + tasklet_kill(&adapter->neq_tasklet); ehea_destroy_eq(adapter->neq); diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 0cfc2bc1a27..37716e05e80 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -94,6 +94,7 @@ static long ehea_plpar_hcall9(unsigned long opcode, { long ret; int i, sleep_msecs; + u8 cb_cat; for (i = 0; i < 5; i++) { ret = plpar_hcall9(opcode, outs, @@ -106,7 +107,13 @@ static long ehea_plpar_hcall9(unsigned long opcode, continue; } - if (ret < H_SUCCESS) + cb_cat = EHEA_BMASK_GET(H_MEHEAPORT_CAT, arg2); + + if ((ret < H_SUCCESS) && !(((ret == H_AUTHORITY) + && (opcode == H_MODIFY_HEA_PORT)) + && (((cb_cat == H_PORT_CB4) && ((arg3 == H_PORT_CB4_JUMBO) + || (arg3 == H_PORT_CB4_SPEED))) || ((cb_cat == H_PORT_CB7) + && (arg3 == H_PORT_CB7_DUCQPN))))) ehea_error("opcode=%lx ret=%lx" " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" @@ -120,7 +127,6 @@ static long ehea_plpar_hcall9(unsigned long opcode, outs[0], outs[1], outs[2], outs[3], outs[4], outs[5], outs[6], outs[7], outs[8]); - return ret; } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 439f4133829..93f2b7a2216 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3,8 +3,7 @@ * * Note: This driver is a cleanroom reimplementation based on reverse * engineered documentation written by Carl-Daniel Hailfinger - * and Andrew de Quincey. It's neither supported nor endorsed - * by NVIDIA Corp. Use at your own risk. + * and Andrew de Quincey. * * NVIDIA, nForce and other NVIDIA marks are trademarks or registered * trademarks of NVIDIA Corporation in the United States and other @@ -14,7 +13,7 @@ * Copyright (C) 2004 Andrew de Quincey (wol support) * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane * IRQ rate fixes, bigendian fixes, cleanups, verification) - * Copyright (c) 2004 NVIDIA Corporation + * Copyright (c) 2004,5,6 NVIDIA Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -235,6 +234,7 @@ enum { #define NVREG_XMITCTL_HOST_SEMA_MASK 0x0000f000 #define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000 #define NVREG_XMITCTL_HOST_LOADED 0x00004000 +#define NVREG_XMITCTL_TX_PATH_EN 0x01000000 NvRegTransmitterStatus = 0x088, #define NVREG_XMITSTAT_BUSY 0x01 @@ -250,6 +250,7 @@ enum { #define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE NvRegReceiverControl = 0x094, #define NVREG_RCVCTL_START 0x01 +#define NVREG_RCVCTL_RX_PATH_EN 0x01000000 NvRegReceiverStatus = 0x98, #define NVREG_RCVSTAT_BUSY 0x01 @@ -1170,16 +1171,21 @@ static void nv_start_rx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 rx_ctrl = readl(base + NvRegReceiverControl); dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); /* Already running? Stop it. */ - if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { - writel(0, base + NvRegReceiverControl); + if ((readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) && !np->mac_in_use) { + rx_ctrl &= ~NVREG_RCVCTL_START; + writel(rx_ctrl, base + NvRegReceiverControl); pci_push(base); } writel(np->linkspeed, base + NvRegLinkSpeed); pci_push(base); - writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); + rx_ctrl |= NVREG_RCVCTL_START; + if (np->mac_in_use) + rx_ctrl &= ~NVREG_RCVCTL_RX_PATH_EN; + writel(rx_ctrl, base + NvRegReceiverControl); dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n", dev->name, np->duplex, np->linkspeed); pci_push(base); @@ -1187,39 +1193,59 @@ static void nv_start_rx(struct net_device *dev) static void nv_stop_rx(struct net_device *dev) { + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 rx_ctrl = readl(base + NvRegReceiverControl); dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name); - writel(0, base + NvRegReceiverControl); + if (!np->mac_in_use) + rx_ctrl &= ~NVREG_RCVCTL_START; + else + rx_ctrl |= NVREG_RCVCTL_RX_PATH_EN; + writel(rx_ctrl, base + NvRegReceiverControl); reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, KERN_INFO "nv_stop_rx: ReceiverStatus remained busy"); udelay(NV_RXSTOP_DELAY2); - writel(0, base + NvRegLinkSpeed); + if (!np->mac_in_use) + writel(0, base + NvRegLinkSpeed); } static void nv_start_tx(struct net_device *dev) { + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 tx_ctrl = readl(base + NvRegTransmitterControl); dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name); - writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); + tx_ctrl |= NVREG_XMITCTL_START; + if (np->mac_in_use) + tx_ctrl &= ~NVREG_XMITCTL_TX_PATH_EN; + writel(tx_ctrl, base + NvRegTransmitterControl); pci_push(base); } static void nv_stop_tx(struct net_device *dev) { + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 tx_ctrl = readl(base + NvRegTransmitterControl); dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name); - writel(0, base + NvRegTransmitterControl); + if (!np->mac_in_use) + tx_ctrl &= ~NVREG_XMITCTL_START; + else + tx_ctrl |= NVREG_XMITCTL_TX_PATH_EN; + writel(tx_ctrl, base + NvRegTransmitterControl); reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); udelay(NV_TXSTOP_DELAY2); - writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); + if (!np->mac_in_use) + writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, + base + NvRegTransmitPoll); } static void nv_txrx_reset(struct net_device *dev) @@ -2576,14 +2602,15 @@ static int nv_napi_poll(struct net_device *dev, int *budget) int pkts, limit = min(*budget, dev->quota); struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + unsigned long flags; pkts = nv_rx_process(dev, limit); if (nv_alloc_rx(dev)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (pkts < limit) { @@ -2591,13 +2618,15 @@ static int nv_napi_poll(struct net_device *dev, int *budget) netif_rx_complete(dev); /* re-enable receive interrupts */ - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); + np->irqmask |= NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); else writel(np->irqmask, base + NvRegIrqMask); - spin_unlock_irq(&np->lock); + + spin_unlock_irqrestore(&np->lock, flags); return 0; } else { /* used up our quantum, so reschedule */ @@ -4146,20 +4175,6 @@ static int nv_mgmt_acquire_sema(struct net_device *dev) return 0; } -/* Indicate to mgmt unit whether driver is loaded or not */ -static void nv_mgmt_driver_loaded(struct net_device *dev, int loaded) -{ - u8 __iomem *base = get_hwbase(dev); - u32 tx_ctrl; - - tx_ctrl = readl(base + NvRegTransmitterControl); - if (loaded) - tx_ctrl |= NVREG_XMITCTL_HOST_LOADED; - else - tx_ctrl &= ~NVREG_XMITCTL_HOST_LOADED; - writel(tx_ctrl, base + NvRegTransmitterControl); -} - static int nv_open(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); @@ -4657,33 +4672,24 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); if (id->driver_data & DEV_HAS_MGMT_UNIT) { - writel(0x1, base + 0x204); pci_push(base); - msleep(500); /* management unit running on the mac? */ - np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST; - if (np->mac_in_use) { - u32 mgmt_sync; - /* management unit setup the phy already? */ - mgmt_sync = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK; - if (mgmt_sync == NVREG_XMITCTL_SYNC_NOT_READY) { - if (!nv_mgmt_acquire_sema(dev)) { - for (i = 0; i < 5000; i++) { - msleep(1); - mgmt_sync = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK; - if (mgmt_sync == NVREG_XMITCTL_SYNC_NOT_READY) - continue; - if (mgmt_sync == NVREG_XMITCTL_SYNC_PHY_INIT) - phyinitialized = 1; - break; + if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) { + np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST; + dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", pci_name(pci_dev), np->mac_in_use); + for (i = 0; i < 5000; i++) { + msleep(1); + if (nv_mgmt_acquire_sema(dev)) { + /* management unit setup the phy already? */ + if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) == + NVREG_XMITCTL_SYNC_PHY_INIT) { + /* phy is inited by mgmt unit */ + phyinitialized = 1; + dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", pci_name(pci_dev)); + } else { + /* we need to init the phy */ } - } else { - /* we need to init the phy */ + break; } - } else if (mgmt_sync == NVREG_XMITCTL_SYNC_PHY_INIT) { - /* phy is inited by SMU */ - phyinitialized = 1; - } else { - /* we need to init the phy */ } } } @@ -4722,10 +4728,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (!phyinitialized) { /* reset it */ phy_init(dev); - } - - if (id->driver_data & DEV_HAS_MGMT_UNIT) { - nv_mgmt_driver_loaded(dev, 1); + } else { + /* see if it is a gigabit phy */ + u32 mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + if (mii_status & PHY_GIGABIT) { + np->gigabit = PHY_GIGABIT; + } } /* set default link speed settings */ @@ -4747,8 +4755,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i out_error: if (phystate_orig) writel(phystate|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); - if (np->mac_in_use) - nv_mgmt_driver_loaded(dev, 0); pci_set_drvdata(pci_dev, NULL); out_freering: free_rings(dev); @@ -4778,9 +4784,6 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) writel(np->orig_mac[0], base + NvRegMacAddrA); writel(np->orig_mac[1], base + NvRegMacAddrB); - if (np->mac_in_use) - nv_mgmt_driver_loaded(dev, 0); - /* free all structures */ free_rings(dev); iounmap(get_hwbase(dev)); diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index c2c5fd419bd..ff683947730 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -104,9 +104,9 @@ static int do_pd_setup(struct fs_enet_private *fep) fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); if (fep->interrupt < 0) return -EINVAL; - + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - fep->fec.fecp =(void*)r->start; + fep->fec.fecp = ioremap(r->start, r->end - r->start + 1); if(fep->fec.fecp == NULL) return -EINVAL; @@ -319,11 +319,14 @@ static void restart(struct net_device *dev) * Clear any outstanding interrupt. */ FW(fecp, ievent, 0xffc0); +#ifndef CONFIG_PPC_MERGE FW(fecp, ivec, (fep->interrupt / 2) << 29); - +#else + FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29); +#endif /* - * adjust to speed (only for DUET & RMII) + * adjust to speed (only for DUET & RMII) */ #ifdef CONFIG_DUET if (fpi->use_rmii) { @@ -418,6 +421,7 @@ static void stop(struct net_device *dev) static void pre_request_irq(struct net_device *dev, int irq) { +#ifndef CONFIG_PPC_MERGE immap_t *immap = fs_enet_immap; u32 siel; @@ -431,6 +435,7 @@ static void pre_request_irq(struct net_device *dev, int irq) siel &= ~(0x80000000 >> (irq & ~1)); out_be32(&immap->im_siu_conf.sc_siel, siel); } +#endif } static void post_free_irq(struct net_device *dev, int irq) diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 95ec5872c50..afd7fca7c6c 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -121,13 +121,13 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - fep->scc.sccp = (void *)r->start; + fep->scc.sccp = ioremap(r->start, r->end - r->start + 1); if (fep->scc.sccp == NULL) return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"); - fep->scc.ep = (void *)r->start; + fep->scc.ep = ioremap(r->start, r->end - r->start + 1); if (fep->scc.ep == NULL) return -EINVAL; @@ -397,6 +397,7 @@ static void stop(struct net_device *dev) static void pre_request_irq(struct net_device *dev, int irq) { +#ifndef CONFIG_PPC_MERGE immap_t *immap = fs_enet_immap; u32 siel; @@ -410,6 +411,7 @@ static void pre_request_irq(struct net_device *dev, int irq) siel &= ~(0x80000000 >> (irq & ~1)); out_be32(&immap->im_siu_conf.sc_siel, siel); } +#endif } static void post_free_irq(struct net_device *dev, int irq) diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index 896aa02000d..feb0ada7a02 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -113,7 +113,7 @@ config SCC_TRXECHO config BAYCOM_SER_FDX tristate "BAYCOM ser12 fullduplex driver for AX.25" - depends on AX25 + depends on AX25 && !S390 select CRC_CCITT ---help--- This is one of two drivers for Baycom style simple amateur radio @@ -133,7 +133,7 @@ config BAYCOM_SER_FDX config BAYCOM_SER_HDX tristate "BAYCOM ser12 halfduplex driver for AX.25" - depends on AX25 + depends on AX25 && !S390 select CRC_CCITT ---help--- This is one of two drivers for Baycom style simple amateur radio @@ -181,7 +181,7 @@ config BAYCOM_EPP config YAM tristate "YAM driver for AX.25" - depends on AX25 + depends on AX25 && !S390 help The YAM is a modem for packet radio which connects to the serial port and includes some of the functions of a Terminal Node diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c index 4a97024061e..9074f76ee2b 100644 --- a/drivers/net/ibm_emac/ibm_emac_phy.c +++ b/drivers/net/ibm_emac/ibm_emac_phy.c @@ -309,7 +309,7 @@ int mii_phy_probe(struct mii_phy *phy, int address) { struct mii_phy_def *def; int i; - u32 id; + int id; phy->autoneg = AUTONEG_DISABLE; phy->advertising = 0; @@ -324,6 +324,8 @@ int mii_phy_probe(struct mii_phy *phy, int address) /* Read ID and find matching entry */ id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); + if (id < 0) + return -ENODEV; for (i = 0; (def = mii_phy_table[i]) != NULL; i++) if ((id & def->phy_id_mask) == def->phy_id) break; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index c26a4b8e552..ca2b21f9d44 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -154,8 +154,8 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) int ret = 0; u32 from = G_TC_FROM(skb->tc_verd); - stats->tx_packets++; - stats->tx_bytes+=skb->len; + stats->rx_packets++; + stats->rx_bytes+=skb->len; if (!from || !skb->input_dev) { dropped: diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 3ca1082ec77..340ee99652e 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -441,25 +441,13 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) goto drop; } - /* Make sure there is room for IrDA-USB header. The actual - * allocation will be done lower in skb_push(). - * Also, we don't use directly skb_cow(), because it require - * headroom >= 16, which force unnecessary copies - Jean II */ - if (skb_headroom(skb) < self->header_length) { - IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); - if (skb_cow(skb, self->header_length)) { - IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); - goto drop; - } - } + memcpy(self->tx_buff + self->header_length, skb->data, skb->len); /* Change setting for next frame */ - if (self->capability & IUC_STIR421X) { __u8 turnaround_time; - __u8* frame; + __u8* frame = self->tx_buff; turnaround_time = get_turnaround_time( skb ); - frame= skb_push(skb, self->header_length); irda_usb_build_header(self, frame, 0); frame[2] = turnaround_time; if ((skb->len != 0) && @@ -472,17 +460,17 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) frame[1] = 0; } } else { - irda_usb_build_header(self, skb_push(skb, self->header_length), 0); + irda_usb_build_header(self, self->tx_buff, 0); } /* FIXME: Make macro out of this one */ ((struct irda_skb_cb *)skb->cb)->context = self; - usb_fill_bulk_urb(urb, self->usbdev, + usb_fill_bulk_urb(urb, self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), - skb->data, IRDA_SKB_MAX_MTU, + self->tx_buff, skb->len + self->header_length, write_bulk_callback, skb); - urb->transfer_buffer_length = skb->len; + /* This flag (URB_ZERO_PACKET) indicates that what we send is not * a continuous stream of data but separate packets. * In this case, the USB layer will insert an empty USB frame (TD) @@ -1455,6 +1443,9 @@ static inline void irda_usb_close(struct irda_usb_cb *self) /* Remove the speed buffer */ kfree(self->speed_buff); self->speed_buff = NULL; + + kfree(self->tx_buff); + self->tx_buff = NULL; } /********************** USB CONFIG SUBROUTINES **********************/ @@ -1524,8 +1515,6 @@ static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_ IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", __FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep); - /* Should be 8, 16, 32 or 64 bytes */ - IRDA_ASSERT(self->bulk_out_mtu == 64, ;); return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0)); } @@ -1753,9 +1742,14 @@ static int irda_usb_probe(struct usb_interface *intf, memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU); + self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length, + GFP_KERNEL); + if (self->tx_buff == NULL) + goto err_out_4; + ret = irda_usb_open(self); if (ret) - goto err_out_4; + goto err_out_5; IRDA_MESSAGE("IrDA: Registered device %s\n", net->name); usb_set_intfdata(intf, self); @@ -1766,14 +1760,14 @@ static int irda_usb_probe(struct usb_interface *intf, self->needspatch = (ret < 0); if (self->needspatch) { IRDA_ERROR("STIR421X: Couldn't upload patch\n"); - goto err_out_5; + goto err_out_6; } /* replace IrDA class descriptor with what patched device is now reporting */ irda_desc = irda_usb_find_class_desc (self->usbintf); if (irda_desc == NULL) { ret = -ENODEV; - goto err_out_5; + goto err_out_6; } if (self->irda_desc) kfree (self->irda_desc); @@ -1782,9 +1776,10 @@ static int irda_usb_probe(struct usb_interface *intf, } return 0; - -err_out_5: +err_out_6: unregister_netdev(self->netdev); +err_out_5: + kfree(self->tx_buff); err_out_4: kfree(self->speed_buff); err_out_3: diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 6b2271f18e7..e846c38224a 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -156,6 +156,7 @@ struct irda_usb_cb { struct irlap_cb *irlap; /* The link layer we are binded to */ struct qos_info qos; char *speed_buff; /* Buffer for speed changes */ + char *tx_buff; struct timeval stamp; struct timeval now; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index c14a74634fd..20d306fea4c 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -59,7 +59,7 @@ #include <asm/byteorder.h> #include <asm/unaligned.h> -MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); +MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 18c68193bf1..e2b1af61845 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -166,7 +166,7 @@ static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev) unsigned i; seq_printf(seq, "\n%s (vid/did: %04x/%04x)\n", - PCIDEV_NAME(pdev), (int)pdev->vendor, (int)pdev->device); + pci_name(pdev), (int)pdev->vendor, (int)pdev->device); seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state); seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n", pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask); @@ -1401,7 +1401,7 @@ static void vlsi_tx_timeout(struct net_device *ndev) if (vlsi_start_hw(idev)) IRDA_ERROR("%s: failed to restart hw - %s(%s) unusable!\n", - __FUNCTION__, PCIDEV_NAME(idev->pdev), ndev->name); + __FUNCTION__, pci_name(idev->pdev), ndev->name); else netif_start_queue(ndev); } @@ -1643,7 +1643,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) pdev->current_state = 0; /* hw must be running now */ IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n", - drivername, PCIDEV_NAME(pdev)); + drivername, pci_name(pdev)); if ( !pci_resource_start(pdev,0) || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { @@ -1728,7 +1728,7 @@ static void __devexit vlsi_irda_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); - IRDA_MESSAGE("%s: %s removed\n", drivername, PCIDEV_NAME(pdev)); + IRDA_MESSAGE("%s: %s removed\n", drivername, pci_name(pdev)); } #ifdef CONFIG_PM @@ -1748,7 +1748,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) if (!ndev) { IRDA_ERROR("%s - %s: no netdevice \n", - __FUNCTION__, PCIDEV_NAME(pdev)); + __FUNCTION__, pci_name(pdev)); return 0; } idev = ndev->priv; @@ -1759,7 +1759,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) pdev->current_state = state.event; } else - IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event); + IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, pci_name(pdev), pdev->current_state, state.event); up(&idev->sem); return 0; } @@ -1787,7 +1787,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) if (!ndev) { IRDA_ERROR("%s - %s: no netdevice \n", - __FUNCTION__, PCIDEV_NAME(pdev)); + __FUNCTION__, pci_name(pdev)); return 0; } idev = ndev->priv; @@ -1795,7 +1795,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) if (pdev->current_state == 0) { up(&idev->sem); IRDA_WARNING("%s - %s: already resumed\n", - __FUNCTION__, PCIDEV_NAME(pdev)); + __FUNCTION__, pci_name(pdev)); return 0; } diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index c37f0bc4c7f..2d3b773d8e3 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -41,39 +41,6 @@ #define PCI_CLASS_SUBCLASS_MASK 0xffff #endif -/* in recent 2.5 interrupt handlers have non-void return value */ -#ifndef IRQ_RETVAL -typedef void irqreturn_t; -#define IRQ_NONE -#define IRQ_HANDLED -#define IRQ_RETVAL(x) -#endif - -/* some stuff need to check kernelversion. Not all 2.5 stuff was present - * in early 2.5.x - the test is merely to separate 2.4 from 2.5 - */ -#include <linux/version.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - -/* PDE() introduced in 2.5.4 */ -#ifdef CONFIG_PROC_FS -#define PDE(inode) ((inode)->i_private) -#endif - -/* irda crc16 calculation exported in 2.5.42 */ -#define irda_calc_crc16(fcs,buf,len) (GOOD_FCS) - -/* we use this for unified pci device name access */ -#define PCIDEV_NAME(pdev) ((pdev)->name) - -#else /* 2.5 or later */ - -/* whatever we get from the associated struct device - bus:slot:dev.fn id */ -#define PCIDEV_NAME(pdev) (pci_name(pdev)) - -#endif - /* ================================================================ */ /* non-standard PCI registers */ diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index d6f4f185bf3..2194b567239 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -73,7 +73,7 @@ #include <asm/abs_addr.h> #include <asm/iseries/mf.h> #include <asm/uaccess.h> - +#include <asm/firmware.h> #include <asm/iseries/hv_lp_config.h> #include <asm/iseries/hv_types.h> #include <asm/iseries/hv_lp_event.h> @@ -1668,7 +1668,7 @@ static struct vio_driver veth_driver = { * Module initialization/cleanup */ -void __exit veth_module_cleanup(void) +static void __exit veth_module_cleanup(void) { int i; struct veth_lpar_connection *cnx; @@ -1697,11 +1697,14 @@ void __exit veth_module_cleanup(void) } module_exit(veth_module_cleanup); -int __init veth_module_init(void) +static int __init veth_module_init(void) { int i; int rc; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + this_lp = HvLpConfig_getLpIndex_outline(); for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) { diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 50ffe90488f..f4aba4355b1 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -171,6 +171,7 @@ struct ixgb_adapter { /* TX */ struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp; + unsigned int restart_queue; unsigned long timeo_start; uint32_t tx_cmd_type; uint64_t hw_csum_tx_good; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index cd22523fb03..82c044d6e08 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -79,6 +79,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { {"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)}, {"tx_deferred_ok", IXGB_STAT(stats.dc)}, {"tx_timeout_count", IXGB_STAT(tx_timeout_count) }, + {"tx_restart_queue", IXGB_STAT(restart_queue) }, {"rx_long_length_errors", IXGB_STAT(stats.roc)}, {"rx_short_length_errors", IXGB_STAT(stats.ruc)}, #ifdef NETIF_F_TSO diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 02089b64e42..ecbf45861c6 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -399,8 +399,9 @@ ixgb_init_rx_addrs(struct ixgb_hw *hw) /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); for(i = 1; i < IXGB_RAR_ENTRIES; i++) { - IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); + /* Write high reg first to disable the AV bit first */ IXGB_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); + IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); } return; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index e628126c9c4..a083a918923 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "1.0.117-k2"DRIVERNAPI +#define DRV_VERSION "1.0.126-k2"DRIVERNAPI char ixgb_driver_version[] = DRV_VERSION; static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -1287,6 +1287,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, struct ixgb_buffer *buffer_info; int len = skb->len; unsigned int offset = 0, size, count = 0, i; + unsigned int mss = skb_shinfo(skb)->gso_size; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; @@ -1298,6 +1299,11 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, while(len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, IXGB_MAX_DATA_PER_TXD); + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ + if (unlikely(mss && !nr_frags && size == len && size > 8)) + size -= 4; + buffer_info->length = size; WARN_ON(buffer_info->dma != 0); buffer_info->dma = @@ -1324,6 +1330,13 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, while(len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, IXGB_MAX_DATA_PER_TXD); + + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ + if (unlikely(mss && !nr_frags && size == len + && size > 8)) + size -= 4; + buffer_info->length = size; buffer_info->dma = pci_map_page(adapter->pdev, @@ -1398,11 +1411,43 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags) IXGB_WRITE_REG(&adapter->hw, TDT, i); } +static int __ixgb_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct ixgb_adapter *adapter = netdev_priv(netdev); + struct ixgb_desc_ring *tx_ring = &adapter->tx_ring; + + netif_stop_queue(netdev); + /* Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. */ + if (likely(IXGB_DESC_UNUSED(tx_ring) < size)) + return -EBUSY; + + /* A reprieve! */ + netif_start_queue(netdev); + ++adapter->restart_queue; + return 0; +} + +static int ixgb_maybe_stop_tx(struct net_device *netdev, + struct ixgb_desc_ring *tx_ring, int size) +{ + if (likely(IXGB_DESC_UNUSED(tx_ring) >= size)) + return 0; + return __ixgb_maybe_stop_tx(netdev, size); +} + + /* Tx Descriptors needed, worst case */ #define TXD_USE_COUNT(S) (((S) >> IXGB_MAX_TXD_PWR) + \ (((S) & (IXGB_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) -#define DESC_NEEDED TXD_USE_COUNT(IXGB_MAX_DATA_PER_TXD) + \ - MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 +#define DESC_NEEDED TXD_USE_COUNT(IXGB_MAX_DATA_PER_TXD) /* skb->date */ + \ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 /* for context */ \ + + 1 /* one more needed for sentinel TSO workaround */ static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) @@ -1430,7 +1475,8 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) spin_lock_irqsave(&adapter->tx_lock, flags); #endif - if(unlikely(IXGB_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED)) { + if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, + DESC_NEEDED))) { netif_stop_queue(netdev); spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_BUSY; @@ -1468,8 +1514,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) #ifdef NETIF_F_LLTX /* Make sure there is space in the ring for the next send. */ - if(unlikely(IXGB_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED)) - netif_stop_queue(netdev); + ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED); spin_unlock_irqrestore(&adapter->tx_lock, flags); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 82c10dec1b5..2b739fd584f 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -229,9 +229,11 @@ struct net_device loopback_dev = { }; /* Setup and register the loopback device. */ -int __init loopback_init(void) +static int __init loopback_init(void) { return register_netdev(&loopback_dev); }; +module_init(loopback_init); + EXPORT_SYMBOL(loopback_dev); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index c41ae4286ee..b3bf8642273 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -314,6 +314,13 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) while (mp->tx_desc_count > 0) { spin_lock_irqsave(&mp->lock, flags); + + /* tx_desc_count might have changed before acquiring the lock */ + if (mp->tx_desc_count <= 0) { + spin_unlock_irqrestore(&mp->lock, flags); + return released; + } + tx_index = mp->tx_used_desc_q; desc = &mp->p_tx_desc_area[tx_index]; cmd_sts = desc->cmd_sts; @@ -332,13 +339,13 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) if (skb) mp->tx_skb[tx_index] = NULL; - spin_unlock_irqrestore(&mp->lock, flags); - if (cmd_sts & ETH_ERROR_SUMMARY) { printk("%s: Error in TX\n", dev->name); mp->stats.tx_errors++; } + spin_unlock_irqrestore(&mp->lock, flags); + if (cmd_sts & ETH_TX_FIRST_DESC) dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); else diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 94ac168be59..61cbd4a6044 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -71,7 +71,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.1.0" +#define MYRI10GE_VERSION_STR "1.2.0" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -199,8 +199,6 @@ struct myri10ge_priv { unsigned long serial_number; int vendor_specific_offset; int fw_multicast_support; - u32 devctl; - u16 msi_flags; u32 read_dma; u32 write_dma; u32 read_write_dma; @@ -228,7 +226,7 @@ module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n"); static int myri10ge_msi = 1; /* enable msi by default */ -module_param(myri10ge_msi, int, S_IRUGO); +module_param(myri10ge_msi, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n"); static int myri10ge_intr_coal_delay = 25; @@ -276,6 +274,10 @@ static int myri10ge_fill_thresh = 256; module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n"); +static int myri10ge_wcfifo = 1; +module_param(myri10ge_wcfifo, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n"); + #define MYRI10GE_FW_OFFSET 1024*1024 #define MYRI10GE_HIGHPART_TO_U32(X) \ (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) @@ -721,12 +723,10 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); mgp->irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0); - if (!mgp->msi_enabled) { - status |= myri10ge_send_cmd - (mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0); - mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0); + status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, + &cmd, 0); + mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0); - } status |= myri10ge_send_cmd (mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0); mgp->intr_coal_delay_ptr = (__iomem __be32 *) (mgp->sram + cmd.data0); @@ -1619,6 +1619,41 @@ static void myri10ge_free_rings(struct net_device *dev) mgp->tx.req_list = NULL; } +static int myri10ge_request_irq(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + int status; + + if (myri10ge_msi) { + status = pci_enable_msi(pdev); + if (status != 0) + dev_err(&pdev->dev, + "Error %d setting up MSI; falling back to xPIC\n", + status); + else + mgp->msi_enabled = 1; + } else { + mgp->msi_enabled = 0; + } + status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, + mgp->dev->name, mgp); + if (status != 0) { + dev_err(&pdev->dev, "failed to allocate IRQ\n"); + if (mgp->msi_enabled) + pci_disable_msi(pdev); + } + return status; +} + +static void myri10ge_free_irq(struct myri10ge_priv *mgp) +{ + struct pci_dev *pdev = mgp->pdev; + + free_irq(pdev->irq, mgp); + if (mgp->msi_enabled) + pci_disable_msi(pdev); +} + static int myri10ge_open(struct net_device *dev) { struct myri10ge_priv *mgp; @@ -1634,10 +1669,13 @@ static int myri10ge_open(struct net_device *dev) status = myri10ge_reset(mgp); if (status != 0) { printk(KERN_ERR "myri10ge: %s: failed reset\n", dev->name); - mgp->running = MYRI10GE_ETH_STOPPED; - return -ENXIO; + goto abort_with_nothing; } + status = myri10ge_request_irq(mgp); + if (status != 0) + goto abort_with_nothing; + /* decide what small buffer size to use. For good TCP rx * performance, it is important to not receive 1514 byte * frames into jumbo buffers, as it confuses the socket buffer @@ -1677,10 +1715,10 @@ static int myri10ge_open(struct net_device *dev) "myri10ge: %s: failed to get ring sizes or locations\n", dev->name); mgp->running = MYRI10GE_ETH_STOPPED; - return -ENXIO; + goto abort_with_irq; } - if (mgp->mtrr >= 0) { + if (myri10ge_wcfifo && mgp->mtrr >= 0) { mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4; mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL; @@ -1708,7 +1746,7 @@ static int myri10ge_open(struct net_device *dev) status = myri10ge_allocate_rings(dev); if (status != 0) - goto abort_with_nothing; + goto abort_with_irq; /* now give firmware buffers sizes, and MTU */ cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN; @@ -1771,6 +1809,9 @@ static int myri10ge_open(struct net_device *dev) abort_with_rings: myri10ge_free_rings(dev); +abort_with_irq: + myri10ge_free_irq(mgp); + abort_with_nothing: mgp->running = MYRI10GE_ETH_STOPPED; return -ENOMEM; @@ -1807,7 +1848,7 @@ static int myri10ge_close(struct net_device *dev) printk(KERN_ERR "myri10ge: %s never got down irq\n", dev->name); netif_tx_disable(dev); - + myri10ge_free_irq(mgp); myri10ge_free_rings(dev); mgp->running = MYRI10GE_ETH_STOPPED; @@ -2481,34 +2522,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) } } -static void myri10ge_save_state(struct myri10ge_priv *mgp) -{ - struct pci_dev *pdev = mgp->pdev; - int cap; - - pci_save_state(pdev); - /* now save PCIe and MSI state that Linux will not - * save for us */ - cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); - pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL, &mgp->devctl); - cap = pci_find_capability(pdev, PCI_CAP_ID_MSI); - pci_read_config_word(pdev, cap + PCI_MSI_FLAGS, &mgp->msi_flags); -} - -static void myri10ge_restore_state(struct myri10ge_priv *mgp) -{ - struct pci_dev *pdev = mgp->pdev; - int cap; - - /* restore PCIe and MSI state that linux will not */ - cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); - pci_write_config_dword(pdev, cap + PCI_CAP_ID_EXP, mgp->devctl); - cap = pci_find_capability(pdev, PCI_CAP_ID_MSI); - pci_write_config_word(pdev, cap + PCI_MSI_FLAGS, mgp->msi_flags); - - pci_restore_state(pdev); -} - #ifdef CONFIG_PM static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state) @@ -2529,11 +2542,10 @@ static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state) rtnl_unlock(); } myri10ge_dummy_rdma(mgp, 0); - free_irq(pdev->irq, mgp); - myri10ge_save_state(mgp); + pci_save_state(pdev); pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; + + return pci_set_power_state(pdev, pci_choose_state(pdev, state)); } static int myri10ge_resume(struct pci_dev *pdev) @@ -2555,34 +2567,33 @@ static int myri10ge_resume(struct pci_dev *pdev) mgp->dev->name); return -EIO; } - myri10ge_restore_state(mgp); + + status = pci_restore_state(pdev); + if (status) + return status; status = pci_enable_device(pdev); - if (status < 0) { + if (status) { dev_err(&pdev->dev, "failed to enable device\n"); - return -EIO; + return status; } pci_set_master(pdev); - status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, - netdev->name, mgp); - if (status != 0) { - dev_err(&pdev->dev, "failed to allocate IRQ\n"); - goto abort_with_enabled; - } - myri10ge_reset(mgp); myri10ge_dummy_rdma(mgp, 1); /* Save configuration space to be restored if the * nic resets due to a parity error */ - myri10ge_save_state(mgp); + pci_save_state(pdev); if (netif_running(netdev)) { rtnl_lock(); - myri10ge_open(netdev); + status = myri10ge_open(netdev); rtnl_unlock(); + if (status != 0) + goto abort_with_enabled; + } netif_device_attach(netdev); @@ -2640,7 +2651,11 @@ static void myri10ge_watchdog(struct work_struct *work) * when the driver was loaded, or the last time the * nic was resumed from power saving mode. */ - myri10ge_restore_state(mgp); + pci_restore_state(mgp->pdev); + + /* save state again for accounting reasons */ + pci_save_state(mgp->pdev); + } else { /* if we get back -1's from our slot, perhaps somebody * powered off our card. Don't try to reset it in @@ -2856,23 +2871,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto abort_with_firmware; } - if (myri10ge_msi) { - status = pci_enable_msi(pdev); - if (status != 0) - dev_err(&pdev->dev, - "Error %d setting up MSI; falling back to xPIC\n", - status); - else - mgp->msi_enabled = 1; - } - - status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, - netdev->name, mgp); - if (status != 0) { - dev_err(&pdev->dev, "failed to allocate IRQ\n"); - goto abort_with_firmware; - } - pci_set_drvdata(pdev, mgp); if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU) myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; @@ -2884,7 +2882,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->hard_start_xmit = myri10ge_xmit; netdev->get_stats = myri10ge_get_stats; netdev->base_addr = mgp->iomem_base; - netdev->irq = pdev->irq; netdev->change_mtu = myri10ge_change_mtu; netdev->set_multicast_list = myri10ge_set_multicast_list; netdev->set_mac_address = myri10ge_set_mac_address; @@ -2894,9 +2891,18 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->poll = myri10ge_poll; netdev->weight = myri10ge_napi_weight; + /* make sure we can get an irq, and that MSI can be + * setup (if available). Also ensure netdev->irq + * is set to correct value if MSI is enabled */ + status = myri10ge_request_irq(mgp); + if (status != 0) + goto abort_with_firmware; + netdev->irq = pdev->irq; + myri10ge_free_irq(mgp); + /* Save configuration space to be restored if the * nic resets due to a parity error */ - myri10ge_save_state(mgp); + pci_save_state(pdev); /* Setup the watchdog timer */ setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer, @@ -2907,19 +2913,17 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) status = register_netdev(netdev); if (status != 0) { dev_err(&pdev->dev, "register_netdev failed: %d\n", status); - goto abort_with_irq; + goto abort_with_state; } dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", (mgp->msi_enabled ? "MSI" : "xPIC"), - pdev->irq, mgp->tx.boundary, mgp->fw_name, + netdev->irq, mgp->tx.boundary, mgp->fw_name, (mgp->mtrr >= 0 ? "Enabled" : "Disabled")); return 0; -abort_with_irq: - free_irq(pdev->irq, mgp); - if (mgp->msi_enabled) - pci_disable_msi(pdev); +abort_with_state: + pci_restore_state(pdev); abort_with_firmware: myri10ge_dummy_rdma(mgp, 0); @@ -2970,12 +2974,12 @@ static void myri10ge_remove(struct pci_dev *pdev) flush_scheduled_work(); netdev = mgp->dev; unregister_netdev(netdev); - free_irq(pdev->irq, mgp); - if (mgp->msi_enabled) - pci_disable_msi(pdev); myri10ge_dummy_rdma(mgp, 0); + /* avoid a memory leak */ + pci_restore_state(pdev); + bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry); dma_free_coherent(&pdev->dev, bytes, mgp->rx_done.entry, mgp->rx_done.bus); diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index b5410bee5f2..e8598b80922 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -63,12 +63,11 @@ #include "netxen_nic_hw.h" -#define NETXEN_NIC_BUILD_NO "1" +#define NETXEN_NIC_BUILD_NO "2" #define _NETXEN_NIC_LINUX_MAJOR 3 #define _NETXEN_NIC_LINUX_MINOR 3 -#define _NETXEN_NIC_LINUX_SUBVERSION 2 -#define NETXEN_NIC_LINUX_VERSIONID "3.3.2" "-" NETXEN_NIC_BUILD_NO -#define NETXEN_NIC_FW_VERSIONID "3.3.2" +#define _NETXEN_NIC_LINUX_SUBVERSION 3 +#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" "-" NETXEN_NIC_BUILD_NO #define RCV_DESC_RINGSIZE \ (sizeof(struct rcv_desc) * adapter->max_rx_desc_count) @@ -137,7 +136,7 @@ extern struct workqueue_struct *netxen_workq; #define THIRD_PAGE_GROUP_SIZE THIRD_PAGE_GROUP_END - THIRD_PAGE_GROUP_START #define MAX_RX_BUFFER_LENGTH 1760 -#define MAX_RX_JUMBO_BUFFER_LENGTH 9046 +#define MAX_RX_JUMBO_BUFFER_LENGTH 8062 #define MAX_RX_LRO_BUFFER_LENGTH ((48*1024)-512) #define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2) #define RX_JUMBO_DMA_MAP_LEN \ @@ -199,9 +198,9 @@ enum { (RCV_DESC_NORMAL))) #define MAX_CMD_DESCRIPTORS 1024 -#define MAX_RCV_DESCRIPTORS 32768 -#define MAX_JUMBO_RCV_DESCRIPTORS 4096 -#define MAX_LRO_RCV_DESCRIPTORS 2048 +#define MAX_RCV_DESCRIPTORS 16384 +#define MAX_JUMBO_RCV_DESCRIPTORS 1024 +#define MAX_LRO_RCV_DESCRIPTORS 64 #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS #define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS #define MAX_RCV_DESC MAX_RCV_DESCRIPTORS @@ -240,49 +239,39 @@ extern unsigned long long netxen_dma_mask; typedef u32 netxen_ctx_msg; -#define _netxen_set_bits(config_word, start, bits, val) {\ - unsigned long long mask = (((1ULL << (bits)) - 1) << (start)); \ - unsigned long long value = (val); \ - (config_word) &= ~mask; \ - (config_word) |= (((value) << (start)) & mask); \ -} - #define netxen_set_msg_peg_id(config_word, val) \ - _netxen_set_bits(config_word, 0, 2, val) + ((config_word) &= ~3, (config_word) |= val & 3) #define netxen_set_msg_privid(config_word) \ - set_bit(2, (unsigned long*)&config_word) + ((config_word) |= 1 << 2) #define netxen_set_msg_count(config_word, val) \ - _netxen_set_bits(config_word, 3, 15, val) + ((config_word) &= ~(0x7fff<<3), (config_word) |= (val & 0x7fff) << 3) #define netxen_set_msg_ctxid(config_word, val) \ - _netxen_set_bits(config_word, 18, 10, val) + ((config_word) &= ~(0x3ff<<18), (config_word) |= (val & 0x3ff) << 18) #define netxen_set_msg_opcode(config_word, val) \ - _netxen_set_bits(config_word, 28, 4, val) + ((config_word) &= ~(0xf<<24), (config_word) |= (val & 0xf) << 24) struct netxen_rcv_context { - u32 rcv_ring_addr_lo; - u32 rcv_ring_addr_hi; - u32 rcv_ring_size; - u32 rsrvd; + __le64 rcv_ring_addr; + __le32 rcv_ring_size; + __le32 rsrvd; }; struct netxen_ring_ctx { /* one command ring */ - u64 cmd_consumer_offset; - u32 cmd_ring_addr_lo; - u32 cmd_ring_addr_hi; - u32 cmd_ring_size; - u32 rsrvd; + __le64 cmd_consumer_offset; + __le64 cmd_ring_addr; + __le32 cmd_ring_size; + __le32 rsrvd; /* three receive rings */ struct netxen_rcv_context rcv_ctx[3]; /* one status ring */ - u32 sts_ring_addr_lo; - u32 sts_ring_addr_hi; - u32 sts_ring_size; + __le64 sts_ring_addr; + __le32 sts_ring_size; - u32 ctx_id; + __le32 ctx_id; } __attribute__ ((aligned(64))); /* @@ -306,81 +295,85 @@ struct netxen_ring_ctx { ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) #define netxen_set_cmd_desc_flags(cmd_desc, val) \ - _netxen_set_bits((cmd_desc)->flags_opcode, 0, 7, val) + ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \ + (cmd_desc)->flags_opcode |= cpu_to_le16((val) & 0x7f)) #define netxen_set_cmd_desc_opcode(cmd_desc, val) \ - _netxen_set_bits((cmd_desc)->flags_opcode, 7, 6, val) + ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x3f<<7), \ + (cmd_desc)->flags_opcode |= cpu_to_le16((val) & (0x3f<<7))) #define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \ - _netxen_set_bits((cmd_desc)->num_of_buffers_total_length, 0, 8, val); + ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xff), \ + (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32((val) & 0xff)) #define netxen_set_cmd_desc_totallength(cmd_desc, val) \ - _netxen_set_bits((cmd_desc)->num_of_buffers_total_length, 8, 24, val); + ((cmd_desc)->num_of_buffers_total_length &= cpu_to_le32(0xff), \ + (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 24)) #define netxen_get_cmd_desc_opcode(cmd_desc) \ - (((cmd_desc)->flags_opcode >> 7) & 0x003F) + ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003F) #define netxen_get_cmd_desc_totallength(cmd_desc) \ - (((cmd_desc)->num_of_buffers_total_length >> 8) & 0x0FFFFFF) + (le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8) struct cmd_desc_type0 { u8 tcp_hdr_offset; /* For LSO only */ u8 ip_hdr_offset; /* For LSO only */ /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */ - u16 flags_opcode; + __le16 flags_opcode; /* Bit pattern: 0-7 total number of segments, 8-31 Total size of the packet */ - u32 num_of_buffers_total_length; + __le32 num_of_buffers_total_length; union { struct { - u32 addr_low_part2; - u32 addr_high_part2; + __le32 addr_low_part2; + __le32 addr_high_part2; }; - u64 addr_buffer2; + __le64 addr_buffer2; }; - u16 reference_handle; /* changed to u16 to add mss */ - u16 mss; /* passed by NDIS_PACKET for LSO */ + __le16 reference_handle; /* changed to u16 to add mss */ + __le16 mss; /* passed by NDIS_PACKET for LSO */ /* Bit pattern 0-3 port, 0-3 ctx id */ u8 port_ctxid; u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ - u16 conn_id; /* IPSec offoad only */ + __le16 conn_id; /* IPSec offoad only */ union { struct { - u32 addr_low_part3; - u32 addr_high_part3; + __le32 addr_low_part3; + __le32 addr_high_part3; }; - u64 addr_buffer3; + __le64 addr_buffer3; }; union { struct { - u32 addr_low_part1; - u32 addr_high_part1; + __le32 addr_low_part1; + __le32 addr_high_part1; }; - u64 addr_buffer1; + __le64 addr_buffer1; }; - u16 buffer1_length; - u16 buffer2_length; - u16 buffer3_length; - u16 buffer4_length; + __le16 buffer1_length; + __le16 buffer2_length; + __le16 buffer3_length; + __le16 buffer4_length; union { struct { - u32 addr_low_part4; - u32 addr_high_part4; + __le32 addr_low_part4; + __le32 addr_high_part4; }; - u64 addr_buffer4; + __le64 addr_buffer4; }; - u64 unused; + __le64 unused; } __attribute__ ((aligned(64))); /* Note: sizeof(rcv_desc) should always be a mutliple of 2 */ struct rcv_desc { - u16 reference_handle; - u16 reserved; - u32 buffer_length; /* allocated buffer length (usually 2K) */ - u64 addr_buffer; + __le16 reference_handle; + __le16 reserved; + __le32 buffer_length; /* allocated buffer length (usually 2K) */ + __le64 addr_buffer; }; /* opcode field in status_desc */ @@ -406,36 +399,36 @@ struct rcv_desc { (((status_desc)->lro & 0x80) >> 7) #define netxen_get_sts_port(status_desc) \ - ((status_desc)->status_desc_data & 0x0F) + (le64_to_cpu((status_desc)->status_desc_data) & 0x0F) #define netxen_get_sts_status(status_desc) \ - (((status_desc)->status_desc_data >> 4) & 0x0F) + ((le64_to_cpu((status_desc)->status_desc_data) >> 4) & 0x0F) #define netxen_get_sts_type(status_desc) \ - (((status_desc)->status_desc_data >> 8) & 0x0F) + ((le64_to_cpu((status_desc)->status_desc_data) >> 8) & 0x0F) #define netxen_get_sts_totallength(status_desc) \ - (((status_desc)->status_desc_data >> 12) & 0xFFFF) + ((le64_to_cpu((status_desc)->status_desc_data) >> 12) & 0xFFFF) #define netxen_get_sts_refhandle(status_desc) \ - (((status_desc)->status_desc_data >> 28) & 0xFFFF) + ((le64_to_cpu((status_desc)->status_desc_data) >> 28) & 0xFFFF) #define netxen_get_sts_prot(status_desc) \ - (((status_desc)->status_desc_data >> 44) & 0x0F) + ((le64_to_cpu((status_desc)->status_desc_data) >> 44) & 0x0F) #define netxen_get_sts_owner(status_desc) \ - (((status_desc)->status_desc_data >> 56) & 0x03) + ((le64_to_cpu((status_desc)->status_desc_data) >> 56) & 0x03) #define netxen_get_sts_opcode(status_desc) \ - (((status_desc)->status_desc_data >> 58) & 0x03F) + ((le64_to_cpu((status_desc)->status_desc_data) >> 58) & 0x03F) #define netxen_clear_sts_owner(status_desc) \ ((status_desc)->status_desc_data &= \ - ~(((unsigned long long)3) << 56 )) + ~cpu_to_le64(((unsigned long long)3) << 56 )) #define netxen_set_sts_owner(status_desc, val) \ ((status_desc)->status_desc_data |= \ - (((unsigned long long)((val) & 0x3)) << 56 )) + cpu_to_le64(((unsigned long long)((val) & 0x3)) << 56 )) struct status_desc { /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length 28-43 reference_handle, 44-47 protocol, 48-52 unused 53-55 desc_cnt, 56-57 owner, 58-63 opcode */ - u64 status_desc_data; - u32 hash_value; + __le64 status_desc_data; + __le32 hash_value; u8 hash_type; u8 msg_type; u8 unused; @@ -852,8 +845,6 @@ struct netxen_adapter { spinlock_t tx_lock; spinlock_t lock; struct work_struct watchdog_task; - struct work_struct tx_timeout_task; - struct net_device *netdev; struct timer_list watchdog_timer; u32 curr_window; @@ -887,7 +878,6 @@ struct netxen_adapter { struct netxen_recv_context recv_ctx[MAX_RCV_CTX]; int is_up; - int number; struct netxen_dummy_dma dummy_dma; /* Context interface shared between card and host */ @@ -950,6 +940,7 @@ struct netxen_port { struct pci_dev *pdev; struct net_device_stats net_stats; struct netxen_port_stats stats; + struct work_struct tx_timeout_task; }; #define PCI_OFFSET_FIRST_RANGE(adapter, off) \ @@ -1008,9 +999,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, long enable); int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg, - __le32 * readval); + __u32 * readval); int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy, - long reg, __le32 val); + long reg, __u32 val); /* Functions available from netxen_nic_hw.c */ int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu); @@ -1027,14 +1018,6 @@ int netxen_nic_hw_read_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); -int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off, - void *data, int len); -int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off, - void *data, int len); -int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter, - u64 off, void *data, int size); void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, int data); @@ -1067,9 +1050,6 @@ void netxen_tso_check(struct netxen_adapter *adapter, struct cmd_desc_type0 *desc, struct sk_buff *skb); int netxen_nic_hw_resources(struct netxen_adapter *adapter); void netxen_nic_clear_stats(struct netxen_adapter *adapter); -int -netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, - struct netxen_port *port); int netxen_nic_rx_has_work(struct netxen_adapter *adapter); int netxen_nic_tx_has_work(struct netxen_adapter *adapter); void netxen_watchdog_task(struct work_struct *work); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 2ab4885cc95..c381d77a733 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -42,7 +42,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic.h" #include "netxen_nic_phan_reg.h" -#include "netxen_nic_ioctl.h" struct netxen_nic_stats { char stat_string[ETH_GSTRING_LEN]; @@ -79,8 +78,7 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { {"tx_bytes", NETXEN_NIC_STAT(stats.txbytes)}, }; -#define NETXEN_NIC_STATS_LEN \ - sizeof(netxen_nic_gstrings_stats) / sizeof(struct netxen_nic_stats) +#define NETXEN_NIC_STATS_LEN ARRAY_SIZE(netxen_nic_gstrings_stats) static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_offline", "EEPROM_Test_offline", @@ -220,7 +218,7 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; - __le32 status; + __u32 status; /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { @@ -228,7 +226,7 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (adapter->phy_write && adapter->phy_write(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - (__le32) ecmd->autoneg) != 0) + ecmd->autoneg) != 0) return -EIO; else port->link_autoneg = ecmd->autoneg; @@ -281,7 +279,7 @@ static int netxen_nic_get_regs_len(struct net_device *dev) } struct netxen_niu_regs { - __le32 reg[NETXEN_NIC_REGS_COUNT]; + __u32 reg[NETXEN_NIC_REGS_COUNT]; }; static struct netxen_niu_regs niu_registers[] = { @@ -374,7 +372,7 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; - __le32 mode, *regs_buff = p; + __u32 mode, *regs_buff = p; void __iomem *addr; int i, window; @@ -417,7 +415,7 @@ static u32 netxen_nic_get_link(struct net_device *dev) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; - __le32 status; + __u32 status; /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { @@ -484,13 +482,13 @@ netxen_nic_get_pauseparam(struct net_device *dev, { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; - __le32 val; + __u32 val; if (adapter->ahw.board_type == NETXEN_NIC_GBE) { /* get flow control settings */ netxen_nic_read_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), - (u32 *) & val); + &val); pause->rx_pause = netxen_gb_get_rx_flowctl(val); pause->tx_pause = netxen_gb_get_tx_flowctl(val); /* get autoneg settings */ @@ -504,7 +502,7 @@ netxen_nic_set_pauseparam(struct net_device *dev, { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; - __le32 val; + __u32 val; unsigned int autoneg; /* read mode */ @@ -524,13 +522,13 @@ netxen_nic_set_pauseparam(struct net_device *dev, netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), - *(u32 *) (&val)); + *&val); /* set autoneg */ autoneg = pause->autoneg; if (adapter->phy_write && adapter->phy_write(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - (__le32) autoneg) != 0) + autoneg) != 0) return -EIO; else { port->link_autoneg = pause->autoneg; @@ -545,7 +543,7 @@ static int netxen_nic_reg_test(struct net_device *dev) struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; u32 data_read, data_written, save; - __le32 mode; + __u32 mode; /* * first test the "Read Only" registers by writing which mode @@ -711,7 +709,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev, (netxen_nic_gstrings_stats[index].sizeof_stat == sizeof(u64)) ? *(u64 *) p : *(u32 *) p; } - } struct ethtool_ops netxen_nic_ethtool_ops = { diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 9147b6048df..f263232f499 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -95,7 +95,7 @@ void netxen_nic_set_multi(struct net_device *netdev) struct netxen_port *port = netdev_priv(netdev); struct netxen_adapter *adapter = port->adapter; struct dev_mc_list *mc_ptr; - __le32 netxen_mac_addr_cntl_data = 0; + __u32 netxen_mac_addr_cntl_data = 0; mc_ptr = netdev->mc_list; if (netdev->flags & IFF_PROMISC) { @@ -236,8 +236,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) } memset(addr, 0, sizeof(struct netxen_ring_ctx)); adapter->ctx_desc = (struct netxen_ring_ctx *)addr; - adapter->ctx_desc->cmd_consumer_offset = adapter->ctx_desc_phys_addr - + sizeof(struct netxen_ring_ctx); + adapter->ctx_desc->cmd_consumer_offset = + cpu_to_le64(adapter->ctx_desc_phys_addr + + sizeof(struct netxen_ring_ctx)); adapter->cmd_consumer = (uint32_t *) (((char *)addr) + sizeof(struct netxen_ring_ctx)); @@ -253,11 +254,10 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) return -ENOMEM; } - adapter->ctx_desc->cmd_ring_addr_lo = - hw->cmd_desc_phys_addr & 0xffffffffUL; - adapter->ctx_desc->cmd_ring_addr_hi = - ((u64) hw->cmd_desc_phys_addr >> 32); - adapter->ctx_desc->cmd_ring_size = adapter->max_tx_desc_count; + adapter->ctx_desc->cmd_ring_addr = + cpu_to_le64(hw->cmd_desc_phys_addr); + adapter->ctx_desc->cmd_ring_size = + cpu_to_le32(adapter->max_tx_desc_count); hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; @@ -278,12 +278,10 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) return err; } rcv_desc->desc_head = (struct rcv_desc *)addr; - adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_lo = - rcv_desc->phys_addr & 0xffffffffUL; - adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_hi = - ((u64) rcv_desc->phys_addr >> 32); + adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr = + cpu_to_le64(rcv_desc->phys_addr); adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size = - rcv_desc->max_rx_desc_count; + cpu_to_le32(rcv_desc->max_rx_desc_count); } addr = netxen_alloc(adapter->ahw.pdev, STATUS_DESC_RINGSIZE, @@ -297,11 +295,10 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) return err; } recv_ctx->rcv_status_desc_head = (struct status_desc *)addr; - adapter->ctx_desc->sts_ring_addr_lo = - recv_ctx->rcv_status_desc_phys_addr & 0xffffffffUL; - adapter->ctx_desc->sts_ring_addr_hi = - ((u64) recv_ctx->rcv_status_desc_phys_addr >> 32); - adapter->ctx_desc->sts_ring_size = adapter->max_rx_desc_count; + adapter->ctx_desc->sts_ring_addr = + cpu_to_le64(recv_ctx->rcv_status_desc_phys_addr); + adapter->ctx_desc->sts_ring_size = + cpu_to_le32(adapter->max_rx_desc_count); } /* Window = 1 */ @@ -376,7 +373,7 @@ void netxen_tso_check(struct netxen_adapter *adapter, ((skb->nh.iph)->ihl * sizeof(u32)) + ((skb->h.th)->doff * sizeof(u32)); netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO); - } else if (skb->ip_summed == CHECKSUM_COMPLETE) { + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->nh.iph->protocol == IPPROTO_TCP) { netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT); } else if (skb->nh.iph->protocol == IPPROTO_UDP) { @@ -387,10 +384,6 @@ void netxen_tso_check(struct netxen_adapter *adapter, } adapter->stats.xmitcsummed++; desc->tcp_hdr_offset = skb->h.raw - skb->data; - netxen_set_cmd_desc_totallength(desc, - cpu_to_le32 - (netxen_get_cmd_desc_totallength - (desc))); desc->ip_hdr_offset = skb->nh.raw - skb->data; } @@ -867,9 +860,9 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, void netxen_nic_set_link_parameters(struct netxen_port *port) { struct netxen_adapter *adapter = port->adapter; - __le32 status; - __le32 autoneg; - __le32 mode; + __u32 status; + __u32 autoneg; + __u32 mode; netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ @@ -984,7 +977,8 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) _NETXEN_NIC_LINUX_MAJOR, fw_major); adapter->driver_mismatch = 1; } - if (fw_minor != _NETXEN_NIC_LINUX_MINOR) { + if (fw_minor != _NETXEN_NIC_LINUX_MINOR && + fw_minor != (_NETXEN_NIC_LINUX_MINOR + 1)) { printk(KERN_ERR "The mismatch in driver version and firmware " "version minor number\n" "Driver version minor number = %d \t" @@ -997,297 +991,3 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) fw_major, fw_minor); } -int netxen_crb_read_val(struct netxen_adapter *adapter, unsigned long off) -{ - int data; - netxen_nic_hw_read_wx(adapter, off, &data, 4); - return data; -} - -int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off, - void *data, int len) -{ - void *addr; - u64 offset = off; - u8 *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - - if (ADDR_IN_WINDOW1(off)) { - addr = NETXEN_CRB_NORMALIZE(adapter, off); - if (!addr) { - mem_base = pci_resource_start(adapter->ahw.pdev, 0); - offset = NETXEN_CRB_NORMAL(off); - mem_page = offset & PAGE_MASK; - if (mem_page != ((offset + len - 1) & PAGE_MASK)) - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { - return 1; - } - addr = mem_ptr; - addr += offset & (PAGE_SIZE - 1); - } - } else { - addr = pci_base_offset(adapter, off); - if (!addr) { - mem_base = pci_resource_start(adapter->ahw.pdev, 0); - mem_page = off & PAGE_MASK; - if (mem_page != ((off + len - 1) & PAGE_MASK)) - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { - return 1; - } - addr = mem_ptr; - addr += off & (PAGE_SIZE - 1); - } - netxen_nic_pci_change_crbwindow(adapter, 0); - } - switch (len) { - case 1: - writeb(*(u8 *) data, addr); - break; - case 2: - writew(*(u16 *) data, addr); - break; - case 4: - writel(*(u32 *) data, addr); - break; - case 8: - writeq(*(u64 *) data, addr); - break; - default: - DPRINTK(INFO, - "writing data %lx to offset %llx, num words=%d\n", - *(unsigned long *)data, off, (len >> 3)); - - netxen_nic_hw_block_write64((u64 __iomem *) data, addr, - (len >> 3)); - break; - } - - if (!ADDR_IN_WINDOW1(off)) - netxen_nic_pci_change_crbwindow(adapter, 1); - if (mem_ptr) - iounmap(mem_ptr); - return 0; -} - -int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off, - void *data, int len) -{ - void *addr; - u64 offset; - u8 *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - - if (ADDR_IN_WINDOW1(off)) { - addr = NETXEN_CRB_NORMALIZE(adapter, off); - if (!addr) { - mem_base = pci_resource_start(adapter->ahw.pdev, 0); - offset = NETXEN_CRB_NORMAL(off); - mem_page = offset & PAGE_MASK; - if (mem_page != ((offset + len - 1) & PAGE_MASK)) - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { - *(u8 *) data = 0; - return 1; - } - addr = mem_ptr; - addr += offset & (PAGE_SIZE - 1); - } - } else { - addr = pci_base_offset(adapter, off); - if (!addr) { - mem_base = pci_resource_start(adapter->ahw.pdev, 0); - mem_page = off & PAGE_MASK; - if (mem_page != ((off + len - 1) & PAGE_MASK)) - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = - ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) - return 1; - addr = mem_ptr; - addr += off & (PAGE_SIZE - 1); - } - netxen_nic_pci_change_crbwindow(adapter, 0); - } - switch (len) { - case 1: - *(u8 *) data = readb(addr); - break; - case 2: - *(u16 *) data = readw(addr); - break; - case 4: - *(u32 *) data = readl(addr); - break; - case 8: - *(u64 *) data = readq(addr); - break; - default: - netxen_nic_hw_block_read64((u64 __iomem *) data, addr, - (len >> 3)); - break; - } - if (!ADDR_IN_WINDOW1(off)) - netxen_nic_pci_change_crbwindow(adapter, 1); - if (mem_ptr) - iounmap(mem_ptr); - return 0; -} - -int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter, u64 off, - void *data, int size) -{ - void *addr; - int ret = 0; - u8 *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - - if (data == NULL || off > (128 * 1024 * 1024)) { - printk(KERN_ERR "%s: data: %p off:%llx\n", - netxen_nic_driver_name, data, off); - return 1; - } - off = netxen_nic_pci_set_window(adapter, off); - /* Corner case : Malicious user tried to break the driver by reading - last few bytes in ranges and tries to read further addresses. - */ - if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) { - printk(KERN_ERR "%s: Invalid access to memory address range" - " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off, - off + size); - return 1; - } - addr = pci_base_offset(adapter, off); - DPRINTK(INFO, "writing data %llx to offset %llx\n", - *(unsigned long long *)data, off); - if (!addr) { - mem_base = pci_resource_start(adapter->ahw.pdev, 0); - mem_page = off & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - consecutive pages. - */ - if (mem_page != ((off + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { - return 1; - } - addr = mem_ptr; - addr += off & (PAGE_SIZE - 1); - } - switch (size) { - case 1: - writeb(*(u8 *) data, addr); - break; - case 2: - writew(*(u16 *) data, addr); - break; - case 4: - writel(*(u32 *) data, addr); - break; - case 8: - writeq(*(u64 *) data, addr); - break; - default: - DPRINTK(INFO, - "writing data %lx to offset %llx, num words=%d\n", - *(unsigned long *)data, off, (size >> 3)); - - netxen_nic_hw_block_write64((u64 __iomem *) data, addr, - (size >> 3)); - break; - } - - if (mem_ptr) - iounmap(mem_ptr); - DPRINTK(INFO, "wrote %llx\n", *(unsigned long long *)data); - - return ret; -} - -int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter, - u64 off, void *data, int size) -{ - void *addr; - int ret = 0; - u8 *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - - if (data == NULL || off > (128 * 1024 * 1024)) { - printk(KERN_ERR "%s: data: %p off:%llx\n", - netxen_nic_driver_name, data, off); - return 1; - } - off = netxen_nic_pci_set_window(adapter, off); - /* Corner case : Malicious user tried to break the driver by reading - last few bytes in ranges and tries to read further addresses. - */ - if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) { - printk(KERN_ERR "%s: Invalid access to memory address range" - " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off, - off + size); - return 1; - } - addr = pci_base_offset(adapter, off); - if (!addr) { - mem_base = pci_resource_start(adapter->ahw.pdev, 0); - mem_page = off & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - consecutive pages. - */ - if (mem_page != ((off + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { - *(u8 *) data = 0; - return 1; - } - addr = mem_ptr; - addr += off & (PAGE_SIZE - 1); - } - switch (size) { - case 1: - *(u8 *) data = readb(addr); - break; - case 2: - *(u16 *) data = readw(addr); - break; - case 4: - *(u32 *) data = readl(addr); - break; - case 8: - *(u64 *) data = readq(addr); - break; - default: - netxen_nic_hw_block_read64((u64 __iomem *) data, addr, - (size >> 3)); - break; - } - - if (mem_ptr) - iounmap(mem_ptr); - DPRINTK(INFO, "read %llx\n", *(unsigned long long *)data); - - return ret; -} diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 0685633a9c1..ab1112eb1b0 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -124,28 +124,28 @@ typedef enum { */ #define netxen_gb_enable_tx(config_word) \ - set_bit(0, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 0) #define netxen_gb_enable_rx(config_word) \ - set_bit(2, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 2) #define netxen_gb_tx_flowctl(config_word) \ - set_bit(4, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 4) #define netxen_gb_rx_flowctl(config_word) \ - set_bit(5, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 5) #define netxen_gb_tx_reset_pb(config_word) \ - set_bit(16, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 16) #define netxen_gb_rx_reset_pb(config_word) \ - set_bit(17, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 17) #define netxen_gb_tx_reset_mac(config_word) \ - set_bit(18, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 18) #define netxen_gb_rx_reset_mac(config_word) \ - set_bit(19, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 19) #define netxen_gb_soft_reset(config_word) \ - set_bit(31, (unsigned long*)(&config_word)) + ((config_word) |= 1 << 31) #define netxen_gb_unset_tx_flowctl(config_word) \ - clear_bit(4, (unsigned long *)(&config_word)) + ((config_word) &= ~(1 << 4)) #define netxen_gb_unset_rx_flowctl(config_word) \ - clear_bit(5, (unsigned long*)(&config_word)) + ((config_word) &= ~(1 << 5)) #define netxen_gb_get_tx_synced(config_word) \ _netxen_crb_get_bit((config_word), 1) @@ -171,15 +171,15 @@ typedef enum { */ #define netxen_gb_set_duplex(config_word) \ - set_bit(0, (unsigned long*)&config_word) + ((config_word) |= 1 << 0) #define netxen_gb_set_crc_enable(config_word) \ - set_bit(1, (unsigned long*)&config_word) + ((config_word) |= 1 << 1) #define netxen_gb_set_padshort(config_word) \ - set_bit(2, (unsigned long*)&config_word) + ((config_word) |= 1 << 2) #define netxen_gb_set_checklength(config_word) \ - set_bit(4, (unsigned long*)&config_word) + ((config_word) |= 1 << 4) #define netxen_gb_set_hugeframes(config_word) \ - set_bit(5, (unsigned long*)&config_word) + ((config_word) |= 1 << 5) #define netxen_gb_set_preamblelen(config_word, val) \ ((config_word) |= ((val) << 12) & 0xF000) #define netxen_gb_set_intfmode(config_word, val) \ @@ -190,9 +190,9 @@ typedef enum { #define netxen_gb_set_mii_mgmt_clockselect(config_word, val) \ ((config_word) |= ((val) & 0x07)) #define netxen_gb_mii_mgmt_reset(config_word) \ - set_bit(31, (unsigned long*)&config_word) + ((config_word) |= 1 << 31) #define netxen_gb_mii_mgmt_unset(config_word) \ - clear_bit(31, (unsigned long*)&config_word) + ((config_word) &= ~(1 << 31)) /* * NIU GB MII Mgmt Command Register (applies to GB0, GB1, GB2, GB3) @@ -201,7 +201,7 @@ typedef enum { */ #define netxen_gb_mii_mgmt_set_read_cycle(config_word) \ - set_bit(0, (unsigned long*)&config_word) + ((config_word) |= 1 << 0) #define netxen_gb_mii_mgmt_reg_addr(config_word, val) \ ((config_word) |= ((val) & 0x1F)) #define netxen_gb_mii_mgmt_phy_addr(config_word, val) \ @@ -274,9 +274,9 @@ typedef enum { #define netxen_set_phy_speed(config_word, val) \ ((config_word) |= ((val & 0x03) << 14)) #define netxen_set_phy_duplex(config_word) \ - set_bit(13, (unsigned long*)&config_word) + ((config_word) |= 1 << 13) #define netxen_clear_phy_duplex(config_word) \ - clear_bit(13, (unsigned long*)&config_word) + ((config_word) &= ~(1 << 13)) #define netxen_get_phy_jabber(config_word) \ _netxen_crb_get_bit(config_word, 0) @@ -350,11 +350,11 @@ typedef enum { _netxen_crb_get_bit(config_word, 15) #define netxen_set_phy_int_link_status_changed(config_word) \ - set_bit(10, (unsigned long*)&config_word) + ((config_word) |= 1 << 10) #define netxen_set_phy_int_autoneg_completed(config_word) \ - set_bit(11, (unsigned long*)&config_word) + ((config_word) |= 1 << 11) #define netxen_set_phy_int_speed_changed(config_word) \ - set_bit(14, (unsigned long*)&config_word) + ((config_word) |= 1 << 14) /* * NIU Mode Register. @@ -382,22 +382,22 @@ typedef enum { */ #define netxen_set_gb_drop_gb0(config_word) \ - set_bit(0, (unsigned long*)&config_word) + ((config_word) |= 1 << 0) #define netxen_set_gb_drop_gb1(config_word) \ - set_bit(1, (unsigned long*)&config_word) + ((config_word) |= 1 << 1) #define netxen_set_gb_drop_gb2(config_word) \ - set_bit(2, (unsigned long*)&config_word) + ((config_word) |= 1 << 2) #define netxen_set_gb_drop_gb3(config_word) \ - set_bit(3, (unsigned long*)&config_word) + ((config_word) |= 1 << 3) #define netxen_clear_gb_drop_gb0(config_word) \ - clear_bit(0, (unsigned long*)&config_word) + ((config_word) &= ~(1 << 0)) #define netxen_clear_gb_drop_gb1(config_word) \ - clear_bit(1, (unsigned long*)&config_word) + ((config_word) &= ~(1 << 1)) #define netxen_clear_gb_drop_gb2(config_word) \ - clear_bit(2, (unsigned long*)&config_word) + ((config_word) &= ~(1 << 2)) #define netxen_clear_gb_drop_gb3(config_word) \ - clear_bit(3, (unsigned long*)&config_word) + ((config_word) &= ~(1 << 3)) /* * NIU XG MAC Config Register @@ -413,7 +413,7 @@ typedef enum { */ #define netxen_xg_soft_reset(config_word) \ - set_bit(4, (unsigned long*)&config_word) + ((config_word) |= 1 << 4) /* * MAC Control Register @@ -433,19 +433,19 @@ typedef enum { #define netxen_nic_mcr_set_id_pool0(config, val) \ ((config) |= ((val) &0x03)) #define netxen_nic_mcr_set_enable_xtnd0(config) \ - (set_bit(3, (unsigned long *)&(config))) + ((config) |= 1 << 3) #define netxen_nic_mcr_set_id_pool1(config, val) \ ((config) |= (((val) & 0x03) << 4)) #define netxen_nic_mcr_set_enable_xtnd1(config) \ - (set_bit(6, (unsigned long *)&(config))) + ((config) |= 1 << 6) #define netxen_nic_mcr_set_id_pool2(config, val) \ ((config) |= (((val) & 0x03) << 8)) #define netxen_nic_mcr_set_enable_xtnd2(config) \ - (set_bit(10, (unsigned long *)&(config))) + ((config) |= 1 << 10) #define netxen_nic_mcr_set_id_pool3(config, val) \ ((config) |= (((val) & 0x03) << 12)) #define netxen_nic_mcr_set_enable_xtnd3(config) \ - (set_bit(14, (unsigned long *)&(config))) + ((config) |= 1 << 14) #define netxen_nic_mcr_set_mode_select(config, val) \ ((config) |= (((val) & 0x03) << 24)) #define netxen_nic_mcr_set_enable_pool(config, val) \ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 869725f0bb1..973af96337a 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -35,7 +35,6 @@ #include <linux/delay.h> #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_ioctl.h" #include "netxen_nic_phan_reg.h" struct crb_addr_pair { @@ -691,8 +690,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter) desc_head = recv_ctx->rcv_status_desc_head; desc = &desc_head[consumer]; - if (((le16_to_cpu(netxen_get_sts_owner(desc))) - & STATUS_OWNER_HOST)) + if (netxen_get_sts_owner(desc) & STATUS_OWNER_HOST) return 1; } @@ -788,11 +786,11 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)]; struct pci_dev *pdev = port->pdev; struct net_device *netdev = port->netdev; - int index = le16_to_cpu(netxen_get_sts_refhandle(desc)); + int index = netxen_get_sts_refhandle(desc); struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); struct netxen_rx_buffer *buffer; struct sk_buff *skb; - u32 length = le16_to_cpu(netxen_get_sts_totallength(desc)); + u32 length = netxen_get_sts_totallength(desc); u32 desc_ctx; struct netxen_rcv_desc_ctx *rcv_desc; int ret; @@ -919,9 +917,7 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) */ while (count < max) { desc = &desc_head[consumer]; - if (! - (le16_to_cpu(netxen_get_sts_owner(desc)) & - STATUS_OWNER_HOST)) { + if (!(netxen_get_sts_owner(desc) & STATUS_OWNER_HOST)) { DPRINTK(ERR, "desc %p ownedby %x\n", desc, netxen_get_sts_owner(desc)); break; @@ -1023,7 +1019,7 @@ int netxen_process_cmd_ring(unsigned long data) && netif_carrier_ok(port->netdev)) && ((jiffies - port->netdev->trans_start) > port->netdev->watchdog_timeo)) { - SCHEDULE_WORK(&port->adapter->tx_timeout_task); + SCHEDULE_WORK(&port->tx_timeout_task); } last_consumer = get_next_index(last_consumer, @@ -1138,13 +1134,13 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) */ dma = pci_map_single(pdev, skb->data, rcv_desc->dma_size, PCI_DMA_FROMDEVICE); - pdesc->addr_buffer = dma; + pdesc->addr_buffer = cpu_to_le64(dma); buffer->skb = skb; buffer->state = NETXEN_BUFFER_BUSY; buffer->dma = dma; /* make a rcv descriptor */ - pdesc->reference_handle = buffer->ref_handle; - pdesc->buffer_length = rcv_desc->dma_size; + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rcv_desc->dma_size); DPRINTK(INFO, "done writing descripter\n"); producer = get_next_index(producer, rcv_desc->max_rx_desc_count); @@ -1232,8 +1228,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, PCI_DMA_FROMDEVICE); /* make a rcv descriptor */ - pdesc->reference_handle = le16_to_cpu(buffer->ref_handle); - pdesc->buffer_length = le16_to_cpu(rcv_desc->dma_size); + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rcv_desc->dma_size); pdesc->addr_buffer = cpu_to_le64(buffer->dma); DPRINTK(INFO, "done writing descripter\n"); producer = @@ -1273,52 +1269,6 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter) return 0; } -int -netxen_nic_fill_statistics(struct netxen_adapter *adapter, - struct netxen_port *port, - struct netxen_statistics *netxen_stats) -{ - void __iomem *addr; - - if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { - netxen_nic_pci_change_crbwindow(adapter, 0); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_BYTE_CNT, - &(netxen_stats->tx_bytes)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_FRAME_CNT, - &(netxen_stats->tx_packets)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_BYTE_CNT, - &(netxen_stats->rx_bytes)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_FRAME_CNT, - &(netxen_stats->rx_packets)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_AGGR_ERROR_CNT, - &(netxen_stats->rx_errors)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_CRC_ERROR_CNT, - &(netxen_stats->rx_crc_errors)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR, - &(netxen_stats-> - rx_long_length_error)); - NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR, - &(netxen_stats-> - rx_short_length_error)); - - netxen_nic_pci_change_crbwindow(adapter, 1); - } else { - spin_lock_bh(&adapter->tx_lock); - netxen_stats->tx_bytes = port->stats.txbytes; - netxen_stats->tx_packets = port->stats.xmitedframes + - port->stats.xmitfinished; - netxen_stats->rx_bytes = port->stats.rxbytes; - netxen_stats->rx_packets = port->stats.no_rcv; - netxen_stats->rx_errors = port->stats.rcvdbadskb; - netxen_stats->tx_errors = port->stats.nocmddescriptor; - netxen_stats->rx_short_length_error = port->stats.uplcong; - netxen_stats->rx_long_length_error = port->stats.uphcong; - netxen_stats->rx_crc_errors = 0; - netxen_stats->rx_mac_errors = 0; - spin_unlock_bh(&adapter->tx_lock); - } - return 0; -} void netxen_nic_clear_stats(struct netxen_adapter *adapter) { @@ -1332,193 +1282,3 @@ void netxen_nic_clear_stats(struct netxen_adapter *adapter) } } -int -netxen_nic_clear_statistics(struct netxen_adapter *adapter, - struct netxen_port *port) -{ - int data = 0; - - netxen_nic_pci_change_crbwindow(adapter, 0); - - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_TX_BYTE_CNT, &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_TX_FRAME_CNT, - &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_RX_BYTE_CNT, &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_RX_FRAME_CNT, - &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_AGGR_ERROR_CNT, - &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_CRC_ERROR_CNT, - &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR, - &data); - netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR, - &data); - - netxen_nic_pci_change_crbwindow(adapter, 1); - netxen_nic_clear_stats(adapter); - return 0; -} - -int -netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data, - struct netxen_port *port) -{ - struct netxen_nic_ioctl_data data; - struct netxen_nic_ioctl_data *up_data; - int retval = 0; - struct netxen_statistics netxen_stats; - - up_data = (void *)u_data; - - DPRINTK(INFO, "doing ioctl for %p\n", adapter); - if (copy_from_user(&data, (void __user *)up_data, sizeof(data))) { - /* evil user tried to crash the kernel */ - DPRINTK(ERR, "bad copy from userland: %d\n", (int)sizeof(data)); - retval = -EFAULT; - goto error_out; - } - - /* Shouldn't access beyond legal limits of "char u[64];" member */ - if (!data.ptr && (data.size > sizeof(data.u))) { - /* evil user tried to crash the kernel */ - DPRINTK(ERR, "bad size: %d\n", data.size); - retval = -EFAULT; - goto error_out; - } - - switch (data.cmd) { - case netxen_nic_cmd_pci_read: - if ((retval = netxen_nic_hw_read_ioctl(adapter, data.off, - &(data.u), data.size))) - goto error_out; - if (copy_to_user - ((void __user *)&(up_data->u), &(data.u), data.size)) { - DPRINTK(ERR, "bad copy to userland: %d\n", - (int)sizeof(data)); - retval = -EFAULT; - goto error_out; - } - data.rv = 0; - break; - - case netxen_nic_cmd_pci_write: - if ((retval = netxen_nic_hw_write_ioctl(adapter, data.off, - &(data.u), data.size))) - goto error_out; - data.rv = 0; - break; - - case netxen_nic_cmd_pci_mem_read: - if (netxen_nic_pci_mem_read_ioctl(adapter, data.off, &(data.u), - data.size)) { - DPRINTK(ERR, "Failed to read the data.\n"); - retval = -EFAULT; - goto error_out; - } - if (copy_to_user - ((void __user *)&(up_data->u), &(data.u), data.size)) { - DPRINTK(ERR, "bad copy to userland: %d\n", - (int)sizeof(data)); - retval = -EFAULT; - goto error_out; - } - data.rv = 0; - break; - - case netxen_nic_cmd_pci_mem_write: - if ((retval = netxen_nic_pci_mem_write_ioctl(adapter, data.off, - &(data.u), - data.size))) - goto error_out; - data.rv = 0; - break; - - case netxen_nic_cmd_pci_config_read: - switch (data.size) { - case 1: - data.rv = pci_read_config_byte(adapter->ahw.pdev, - data.off, - (char *)&(data.u)); - break; - case 2: - data.rv = pci_read_config_word(adapter->ahw.pdev, - data.off, - (short *)&(data.u)); - break; - case 4: - data.rv = pci_read_config_dword(adapter->ahw.pdev, - data.off, - (u32 *) & (data.u)); - break; - } - if (copy_to_user - ((void __user *)&(up_data->u), &(data.u), data.size)) { - DPRINTK(ERR, "bad copy to userland: %d\n", - (int)sizeof(data)); - retval = -EFAULT; - goto error_out; - } - break; - - case netxen_nic_cmd_pci_config_write: - switch (data.size) { - case 1: - data.rv = pci_write_config_byte(adapter->ahw.pdev, - data.off, - *(char *)&(data.u)); - break; - case 2: - data.rv = pci_write_config_word(adapter->ahw.pdev, - data.off, - *(short *)&(data.u)); - break; - case 4: - data.rv = pci_write_config_dword(adapter->ahw.pdev, - data.off, - *(u32 *) & (data.u)); - break; - } - break; - - case netxen_nic_cmd_get_stats: - data.rv = - netxen_nic_fill_statistics(adapter, port, &netxen_stats); - if (copy_to_user - ((void __user *)(up_data->ptr), (void *)&netxen_stats, - sizeof(struct netxen_statistics))) { - DPRINTK(ERR, "bad copy to userland: %d\n", - (int)sizeof(netxen_stats)); - retval = -EFAULT; - goto error_out; - } - up_data->rv = data.rv; - break; - - case netxen_nic_cmd_clear_stats: - data.rv = netxen_nic_clear_statistics(adapter, port); - up_data->rv = data.rv; - break; - - case netxen_nic_cmd_get_version: - if (copy_to_user - ((void __user *)&(up_data->u), NETXEN_NIC_LINUX_VERSIONID, - sizeof(NETXEN_NIC_LINUX_VERSIONID))) { - DPRINTK(ERR, "bad copy to userland: %d\n", - (int)sizeof(data)); - retval = -EFAULT; - goto error_out; - } - break; - - default: - DPRINTK(INFO, "bad command %d for %p\n", data.cmd, adapter); - retval = -EOPNOTSUPP; - goto error_out; - } - put_user(data.rv, (&(up_data->rv))); - DPRINTK(INFO, "done ioctl for %p well.\n", adapter); - - error_out: - return retval; -} diff --git a/drivers/net/netxen/netxen_nic_ioctl.h b/drivers/net/netxen/netxen_nic_ioctl.h deleted file mode 100644 index 1221fa52755..00000000000 --- a/drivers/net/netxen/netxen_nic_ioctl.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2003 - 2006 NetXen, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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. - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE. - * - * Contact Information: - * info@netxen.com - * NetXen, - * 3965 Freedom Circle, Fourth floor, - * Santa Clara, CA 95054 - */ - -#ifndef __NETXEN_NIC_IOCTL_H__ -#define __NETXEN_NIC_IOCTL_H__ - -#include <linux/sockios.h> - -#define NETXEN_CMD_START SIOCDEVPRIVATE -#define NETXEN_NIC_CMD (NETXEN_CMD_START + 1) -#define NETXEN_NIC_NAME (NETXEN_CMD_START + 2) -#define NETXEN_NIC_NAME_LEN 16 -#define NETXEN_NIC_NAME_RSP "NETXEN-UNM" - -typedef enum { - netxen_nic_cmd_none = 0, - netxen_nic_cmd_pci_read, - netxen_nic_cmd_pci_write, - netxen_nic_cmd_pci_mem_read, - netxen_nic_cmd_pci_mem_write, - netxen_nic_cmd_pci_config_read, - netxen_nic_cmd_pci_config_write, - netxen_nic_cmd_get_stats, - netxen_nic_cmd_clear_stats, - netxen_nic_cmd_get_version -} netxen_nic_ioctl_cmd_t; - -struct netxen_nic_ioctl_data { - u32 cmd; - u32 unused1; - u64 off; - u32 size; - u32 rv; - char u[64]; - void *ptr; -}; - -struct netxen_statistics { - u64 rx_packets; - u64 tx_packets; - u64 rx_bytes; - u64 rx_errors; - u64 tx_bytes; - u64 tx_errors; - u64 rx_crc_errors; - u64 rx_short_length_error; - u64 rx_long_length_error; - u64 rx_mac_errors; -}; - -#endif /* __NETXEN_NIC_IOCTL_H_ */ diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c index 1b45f50fa6a..be366e48007 100644 --- a/drivers/net/netxen/netxen_nic_isr.c +++ b/drivers/net/netxen/netxen_nic_isr.c @@ -79,7 +79,7 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno, void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, u32 enable) { - __le32 int_src; + __u32 int_src; struct netxen_port *port; /* This should clear the interrupt source */ @@ -110,7 +110,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, /* write it down later.. */ if ((netxen_get_phy_int_speed_changed(int_src)) || (netxen_get_phy_int_link_status_changed(int_src))) { - __le32 status; + __u32 status; DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); @@ -157,7 +157,8 @@ void netxen_nic_isr_other(struct netxen_adapter *adapter) for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) { linkup = val & 1; if (linkup != (qg_linksup & 1)) { - printk(KERN_INFO "%s: PORT %d link %s\n", + printk(KERN_INFO "%s: %s PORT %d link %s\n", + adapter->port[portno]->netdev->name, netxen_nic_driver_name, portno, ((linkup == 0) ? "down" : "up")); netxen_indicate_link_status(adapter, portno, linkup); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 575b71b6720..69c1b9d23a1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -38,7 +38,6 @@ #include "netxen_nic.h" #define DEFINE_GLOBAL_RECV_CRB #include "netxen_nic_phan_reg.h" -#include "netxen_nic_ioctl.h" #include <linux/dma-mapping.h> #include <linux/vmalloc.h> @@ -53,8 +52,6 @@ char netxen_nic_driver_name[] = "netxen-nic"; static char netxen_nic_driver_string[] = "NetXen Network Driver version " NETXEN_NIC_LINUX_VERSIONID; -struct netxen_adapter *g_adapter = NULL; - #define NETXEN_NETDEV_WEIGHT 120 #define NETXEN_ADAPTER_UP_MAGIC 777 #define NETXEN_NIC_PEG_TUNE 0 @@ -75,8 +72,6 @@ static void netxen_tx_timeout(struct net_device *netdev); static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_handle_int(struct netxen_adapter *, struct net_device *); -static int netxen_nic_ioctl(struct net_device *netdev, - struct ifreq *ifr, int cmd); static int netxen_nic_poll(struct net_device *dev, int *budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); @@ -90,6 +85,8 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = { {PCI_DEVICE(0x4040, 0x0003)}, {PCI_DEVICE(0x4040, 0x0004)}, {PCI_DEVICE(0x4040, 0x0005)}, + {PCI_DEVICE(0x4040, 0x0024)}, + {PCI_DEVICE(0x4040, 0x0025)}, {0,} }; @@ -120,7 +117,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *mem_ptr1 = NULL; void __iomem *mem_ptr2 = NULL; - u8 *db_ptr = NULL; + u8 __iomem *db_ptr = NULL; unsigned long mem_base, mem_len, db_base, db_len; int pci_using_dac, i, err; int ring; @@ -129,7 +126,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct netxen_cmd_buffer *cmd_buf_arr = NULL; u64 mac_addr[FLASH_NUM_PORTS + 1]; int valid_mac = 0; - static int netxen_cards_found = 0; printk(KERN_INFO "%s \n", netxen_nic_driver_string); /* In current scheme, we use only PCI function 0 */ @@ -195,7 +191,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) db_len); db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES); - if (db_ptr == 0UL) { + if (!db_ptr) { printk(KERN_ERR "%s: Failed to allocate doorbell map.", netxen_nic_driver_name); err = -EIO; @@ -220,9 +216,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_dbunmap; } - if (netxen_cards_found == 0) { - g_adapter = adapter; - } adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS; adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS; @@ -383,7 +376,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->set_multicast_list = netxen_nic_set_multi; netdev->set_mac_address = netxen_nic_set_mac; netdev->change_mtu = netxen_nic_change_mtu; - netdev->do_ioctl = netxen_nic_ioctl; netdev->tx_timeout = netxen_tx_timeout; netdev->watchdog_timeo = HZ; @@ -428,8 +420,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->dev_addr); } } - adapter->netdev = netdev; - INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); + INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -444,6 +435,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->port[i] = port; } + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); + netxen_pinit_from_rom(adapter, 0); + udelay(500); + netxen_load_firmware(adapter); + netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); /* * delay a while to ensure that the Pegs are up & running. * Otherwise, we might see some flaky behaviour. @@ -461,7 +457,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - adapter->number = netxen_cards_found; adapter->driver_mismatch = 0; return 0; @@ -531,6 +526,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_nic_stop_all_ports(adapter); /* leave the hw in the same state as reboot */ + netxen_pinit_from_rom(adapter, 0); + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); netxen_load_firmware(adapter); netxen_free_adapter_offload(adapter); @@ -822,7 +819,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) pbuf = &adapter->cmd_buf_arr[producer]; if ((netdev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size > 0) { pbuf->mss = skb_shinfo(skb)->gso_size; - hwdesc->mss = skb_shinfo(skb)->gso_size; + hwdesc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); } else { pbuf->mss = 0; hwdesc->mss = 0; @@ -885,7 +882,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) hwdesc->addr_buffer3 = cpu_to_le64(temp_dma); break; case 3: - hwdesc->buffer4_length = temp_len; + hwdesc->buffer4_length = cpu_to_le16(temp_len); hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); break; } @@ -956,11 +953,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static void netxen_watchdog(unsigned long v) { struct netxen_adapter *adapter = (struct netxen_adapter *)v; - if (adapter != g_adapter) { - printk("%s: ***BUG*** adapter[%p] != g_adapter[%p]\n", - __FUNCTION__, adapter, g_adapter); - return; - } SCHEDULE_WORK(&adapter->watchdog_task); } @@ -969,23 +961,23 @@ static void netxen_tx_timeout(struct net_device *netdev) { struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); - SCHEDULE_WORK(&port->adapter->tx_timeout_task); + SCHEDULE_WORK(&port->tx_timeout_task); } static void netxen_tx_timeout_task(struct work_struct *work) { - struct netxen_adapter *adapter = - container_of(work, struct netxen_adapter, tx_timeout_task); - struct net_device *netdev = adapter->netdev; + struct netxen_port *port = + container_of(work, struct netxen_port, tx_timeout_task); + struct net_device *netdev = port->netdev; unsigned long flags; printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", netxen_nic_driver_name, netdev->name); - spin_lock_irqsave(&adapter->lock, flags); + spin_lock_irqsave(&port->adapter->lock, flags); netxen_nic_close(netdev); netxen_nic_open(netdev); - spin_unlock_irqrestore(&adapter->lock, flags); + spin_unlock_irqrestore(&port->adapter->lock, flags); netdev->trans_start = jiffies; netif_wake_queue(netdev); } @@ -1137,47 +1129,6 @@ static void netxen_nic_poll_controller(struct net_device *netdev) enable_irq(adapter->irq); } #endif -/* - * netxen_nic_ioctl () We provide the tcl/phanmon support through these - * ioctls. - */ -static int -netxen_nic_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - int err = 0; - unsigned long nr_bytes = 0; - struct netxen_port *port = netdev_priv(netdev); - struct netxen_adapter *adapter = port->adapter; - char dev_name[NETXEN_NIC_NAME_LEN]; - - DPRINTK(INFO, "doing ioctl for %s\n", netdev->name); - switch (cmd) { - case NETXEN_NIC_CMD: - err = netxen_nic_do_ioctl(adapter, (void *)ifr->ifr_data, port); - break; - - case NETXEN_NIC_NAME: - DPRINTK(INFO, "ioctl cmd for NetXen\n"); - if (ifr->ifr_data) { - sprintf(dev_name, "%s-%d", NETXEN_NIC_NAME_RSP, - port->portnum); - nr_bytes = - copy_to_user((char __user *)ifr->ifr_data, dev_name, - NETXEN_NIC_NAME_LEN); - if (nr_bytes) - err = -EIO; - - } - break; - - default: - DPRINTK(INFO, "ioctl cmd %x not supported\n", cmd); - err = -EOPNOTSUPP; - break; - } - - return err; -} static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, @@ -1193,7 +1144,7 @@ static int __init netxen_init_module(void) if ((netxen_workq = create_singlethread_workqueue("netxen")) == 0) return -ENOMEM; - return pci_module_init(&netxen_driver); + return pci_register_driver(&netxen_driver); } module_init(netxen_init_module); diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 4987dc765d9..40d7003a371 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -89,15 +89,15 @@ static inline int phy_unlock(struct netxen_adapter *adapter) * */ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, - long reg, __le32 * readval) + long reg, __u32 * readval) { long timeout = 0; long result = 0; long restore = 0; - __le32 address; - __le32 command; - __le32 status; - __le32 mac_cfg0; + __u32 address; + __u32 command; + __u32 status; + __u32 mac_cfg0; if (phy_lock(adapter) != 0) { return -1; @@ -112,7 +112,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, &mac_cfg0, 4)) return -EIO; if (netxen_gb_get_soft_reset(mac_cfg0)) { - __le32 temp; + __u32 temp; temp = 0; netxen_gb_tx_reset_pb(temp); netxen_gb_rx_reset_pb(temp); @@ -184,15 +184,15 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, * */ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, - long phy, long reg, __le32 val) + long phy, long reg, __u32 val) { long timeout = 0; long result = 0; long restore = 0; - __le32 address; - __le32 command; - __le32 status; - __le32 mac_cfg0; + __u32 address; + __u32 command; + __u32 status; + __u32 mac_cfg0; /* * MII mgmt all goes through port 0 MAC interface, so it @@ -203,7 +203,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, &mac_cfg0, 4)) return -EIO; if (netxen_gb_get_soft_reset(mac_cfg0)) { - __le32 temp; + __u32 temp; temp = 0; netxen_gb_tx_reset_pb(temp); netxen_gb_rx_reset_pb(temp); @@ -269,7 +269,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, int port) { int result = 0; - __le32 enable = 0; + __u32 enable = 0; netxen_set_phy_int_link_status_changed(enable); netxen_set_phy_int_autoneg_completed(enable); netxen_set_phy_int_speed_changed(enable); @@ -402,7 +402,7 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) { int result = 0; - __le32 status; + __u32 status; if (adapter->disable_phy_interrupts) adapter->disable_phy_interrupts(adapter, port); mdelay(2); @@ -410,7 +410,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) if (0 == netxen_niu_gbe_phy_read(adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - (__le32 *) & status)) { + &status)) { if (netxen_get_phy_link(status)) { if (netxen_get_phy_speed(status) == 2) { netxen_niu_gbe_set_gmii_mode(adapter, port, 1); @@ -489,7 +489,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, int port, long enable) { int result = 0; - __le32 int_src; + __u32 int_src; printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d" " (device enable = %d)\n", (int)port, (int)enable); @@ -530,7 +530,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, printk(KERN_INFO PFX "autoneg_error "); if ((netxen_get_phy_int_speed_changed(int_src)) || (netxen_get_phy_int_link_status_changed(int_src))) { - __le32 status; + __u32 status; printk(KERN_INFO PFX "speed_changed or link status changed"); @@ -583,9 +583,9 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int phy, netxen_ethernet_macaddr_t * addr) { - u64 result = 0; - __le32 stationhigh; - __le32 stationlow; + u32 stationhigh; + u32 stationlow; + u8 val[8]; if (addr == NULL) return -EINVAL; @@ -598,10 +598,10 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter, if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &stationlow, 4)) return -EIO; + ((__le32 *)val)[1] = cpu_to_le32(stationhigh); + ((__le32 *)val)[0] = cpu_to_le32(stationlow); - result = (u64) netxen_gb_get_stationaddress_low(stationlow); - result |= (u64) stationhigh << 16; - memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t)); + memcpy(addr, val + 2, 6); return 0; } @@ -613,24 +613,25 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int netxen_niu_macaddr_set(struct netxen_port *port, netxen_ethernet_macaddr_t addr) { - __le32 temp = 0; + u8 temp[4]; + u32 val; struct netxen_adapter *adapter = port->adapter; int phy = port->portnum; unsigned char mac_addr[6]; int i; for (i = 0; i < 10; i++) { - memcpy(&temp, addr, 2); - temp <<= 16; + temp[0] = temp[1] = 0; + memcpy(temp + 2, addr, 2); + val = le32_to_cpu(*(__le32 *)temp); if (netxen_nic_hw_write_wx - (adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &temp, 4)) + (adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &val, 4)) return -EIO; - temp = 0; - - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); + memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); + val = le32_to_cpu(*(__le32 *)temp); if (netxen_nic_hw_write_wx - (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &temp, 4)) + (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) return -2; netxen_niu_macaddr_get(adapter, phy, @@ -659,9 +660,9 @@ int netxen_niu_macaddr_set(struct netxen_port *port, int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, int port, netxen_niu_gbe_ifmode_t mode) { - __le32 mac_cfg0; - __le32 mac_cfg1; - __le32 mii_cfg; + __u32 mac_cfg0; + __u32 mac_cfg1; + __u32 mii_cfg; if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; @@ -736,7 +737,7 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, /* Disable a GbE interface */ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port) { - __le32 mac_cfg0; + __u32 mac_cfg0; if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; @@ -752,7 +753,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port) /* Disable an XG interface */ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port) { - __le32 mac_cfg; + __u32 mac_cfg; if (port != 0) return -EINVAL; @@ -769,7 +770,7 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port) int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, netxen_niu_prom_mode_t mode) { - __le32 reg; + __u32 reg; if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; @@ -826,22 +827,21 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, int netxen_niu_xg_macaddr_set(struct netxen_port *port, netxen_ethernet_macaddr_t addr) { - __le32 temp = 0; + u8 temp[4]; + u32 val; struct netxen_adapter *adapter = port->adapter; - memcpy(&temp, addr, 2); - temp = cpu_to_le32(temp); - temp <<= 16; + temp[0] = temp[1] = 0; + memcpy(temp + 2, addr, 2); + val = le32_to_cpu(*(__le32 *)temp); if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, - &temp, 4)) + &val, 4)) return -EIO; - temp = 0; - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - temp = cpu_to_le32(temp); + val = le32_to_cpu(*(__le32 *)temp); if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, - &temp, 4)) + &val, 4)) return -EIO; return 0; @@ -854,9 +854,9 @@ int netxen_niu_xg_macaddr_set(struct netxen_port *port, int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, netxen_ethernet_macaddr_t * addr) { - __le32 stationhigh; - __le32 stationlow; - u64 result; + u32 stationhigh; + u32 stationlow; + u8 val[8]; if (addr == NULL) return -EINVAL; @@ -869,10 +869,10 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, &stationlow, 4)) return -EIO; + ((__le32 *)val)[1] = cpu_to_le32(stationhigh); + ((__le32 *)val)[0] = cpu_to_le32(stationlow); - result = ((u64) stationlow) >> 16; - result |= (u64) stationhigh << 16; - memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t)); + memcpy(addr, val + 2, 6); return 0; } @@ -880,7 +880,7 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, int port, netxen_niu_prom_mode_t mode) { - __le32 reg; + __u32 reg; if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 794cc61819d..448bf4a7801 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -281,7 +281,6 @@ static int tc574_probe(struct pcmcia_device *link) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; /* The EL3-specific entries in the device structure. */ dev->hard_start_xmit = &el3_start_xmit; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 1e73ff7d5d8..461e8274ef6 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -195,7 +195,6 @@ static int tc589_probe(struct pcmcia_device *link) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; /* The EL3-specific entries in the device structure. */ SET_MODULE_OWNER(dev); @@ -607,11 +606,14 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { kio_addr_t ioaddr = dev->base_addr; struct el3_private *priv = netdev_priv(dev); + unsigned long flags; DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, inw(ioaddr + EL3_STATUS)); + spin_lock_irqsave(&priv->lock, flags); + priv->stats.tx_bytes += skb->len; /* Put out the doubleword header... */ @@ -629,6 +631,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); pop_tx_status(dev); + spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -730,14 +733,13 @@ static void media_check(unsigned long arg) if (!netif_device_present(dev)) goto reschedule; - EL3WINDOW(1); /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, lp); + el3_interrupt(dev->irq, dev); lp->fast_poll = HZ; } if (lp->fast_poll) { diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 91f65e91cd5..0d1c7a41c9c 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -173,7 +173,6 @@ static int com20020_probe(struct pcmcia_device *p_dev) p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; - p_dev->conf.Present = PRESENT_OPTION; p_dev->irq.Instance = info->dev = dev; p_dev->priv = info; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 2b1238e2dbd..d88e9b2e93c 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1617,6 +1617,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9), PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2), PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2), + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "(CG-LAPCCTXD)", 0x5261440f, 0x73ec0d88), PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04), PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d), PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814), @@ -1667,6 +1668,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737), PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TE", 0x88fcdeda, 0x0e714bee), PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922), + PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN10TE", 0x88fcdeda, 0xc1e2521c), PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0), PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578), PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307), diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 8478dca3d8d..5879e7c3698 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -576,7 +576,6 @@ xirc2ps_probe(struct pcmcia_device *link) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; link->irq.Handler = xirc2ps_interrupt; link->irq.Instance = dev; diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 096d4a100bf..86135397f43 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -349,7 +349,7 @@ static int __init fixed_init(void) fixed_mdio_register_device(0, 100, 1); #endif -#ifdef CONFIX_FIXED_MII_10_FDX +#ifdef CONFIG_FIXED_MII_10_FDX fixed_mdio_register_device(0, 10, 1); #endif return 0; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e175f3910b1..9765fa66146 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -286,6 +286,7 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) return 0; } +EXPORT_SYMBOL(phy_ethtool_sset); int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) { @@ -302,7 +303,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) return 0; } - +EXPORT_SYMBOL(phy_ethtool_gset); /* Note that this function is currently incompatible with the * PHYCONTROL layer. It changes registers without regard to diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index d79d141a601..8844c20eac2 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -208,6 +208,15 @@ static void ql_write_common_reg(struct ql3_adapter *qdev, return; } +static void ql_write_nvram_reg(struct ql3_adapter *qdev, + u32 __iomem *reg, u32 value) +{ + writel(value, reg); + readl(reg); + udelay(1); + return; +} + static void ql_write_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg, u32 value) { @@ -336,9 +345,9 @@ static void fm93c56a_select(struct ql3_adapter *qdev) qdev->mem_map_registers; qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1; - ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, ISP_NVRAM_MASK | qdev->eeprom_cmd_data); - ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data)); } @@ -355,14 +364,14 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr) qdev->mem_map_registers; /* Clock in a zero, then do the start bit */ - ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, ISP_NVRAM_MASK | qdev->eeprom_cmd_data | AUBURN_EEPROM_DO_1); - ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> eeprom_cmd_data | AUBURN_EEPROM_DO_1 | AUBURN_EEPROM_CLK_RISE); - ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> eeprom_cmd_data | AUBURN_EEPROM_DO_1 | AUBURN_EEPROM_CLK_FALL); @@ -378,20 +387,20 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr) * If the bit changed, then change the DO state to * match */ - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> eeprom_cmd_data | dataBit); previousBit = dataBit; } - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> eeprom_cmd_data | dataBit | AUBURN_EEPROM_CLK_RISE); - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> @@ -412,20 +421,20 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr) * If the bit changed, then change the DO state to * match */ - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> eeprom_cmd_data | dataBit); previousBit = dataBit; } - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> eeprom_cmd_data | dataBit | AUBURN_EEPROM_CLK_RISE); - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev-> @@ -443,7 +452,7 @@ static void fm93c56a_deselect(struct ql3_adapter *qdev) struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0; - ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, ISP_NVRAM_MASK | qdev->eeprom_cmd_data); } @@ -461,12 +470,12 @@ static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value) /* Read the data bits */ /* The first bit is a dummy. Clock right over it. */ for (i = 0; i < dataBits; i++) { - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev->eeprom_cmd_data | AUBURN_EEPROM_CLK_RISE); - ql_write_common_reg(qdev, + ql_write_nvram_reg(qdev, &port_regs->CommonRegs. serialPortInterfaceReg, ISP_NVRAM_MASK | qdev->eeprom_cmd_data | @@ -3370,7 +3379,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - ndev->features = NETIF_F_LLTX; if (pci_using_dac) ndev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index f83b41d4cb0..577babd4c93 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -225,7 +225,6 @@ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); static int rx_copybreak = 200; static int use_dac; -static int ignore_parity_err; static struct { u32 msg_enable; } debug = { -1 }; @@ -471,8 +470,6 @@ module_param(use_dac, int, 0); MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); module_param_named(debug, debug.msg_enable, int, 0); MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); -module_param_named(ignore_parity_err, ignore_parity_err, bool, 0); -MODULE_PARM_DESC(ignore_parity_err, "Ignore PCI parity error as target. Default: false"); MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); @@ -1885,7 +1882,6 @@ static void rtl8169_hw_start(struct net_device *dev) (tp->mac_version == RTL_GIGA_MAC_VER_02) || (tp->mac_version == RTL_GIGA_MAC_VER_03) || (tp->mac_version == RTL_GIGA_MAC_VER_04)) - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); rtl8169_set_rx_tx_config_registers(tp); cmd = RTL_R16(CPlusCmd); @@ -2388,7 +2384,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) * * Feel free to adjust to your needs. */ - if (ignore_parity_err) + if (pdev->broken_parity_status) pci_cmd &= ~PCI_COMMAND_PARITY; else pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 250cdbeefdf..1dd66b8ea0f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -556,10 +556,9 @@ static int init_shared_mem(struct s2io_nic *nic) } } - nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL); + nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL); if (!nic->ufo_in_band_v) return -ENOMEM; - memset(nic->ufo_in_band_v, 0, size); /* Allocation and initialization of RXDs in Rings */ size = 0; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index b70ed79d412..45d91b15910 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1562,7 +1562,7 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, for (i = 0; i < MAC_ADDR_LEN / 2; i++) { __le16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); - ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); + ((u16 *)dev->dev_addr)[i] = le16_to_cpu(w); } sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo)); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 8a39376f87d..45283f3f95e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -60,7 +60,7 @@ #define LINK_HZ (HZ/2) MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); -MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); +MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); @@ -2920,6 +2920,7 @@ static int skge_poll(struct net_device *dev, int *budget) struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; + unsigned long flags; int to_do = min(dev->quota, *budget); int work_done = 0; @@ -2957,12 +2958,12 @@ static int skge_poll(struct net_device *dev, int *budget) if (work_done >= to_do) return 1; /* not done */ - spin_lock_irq(&hw->hw_lock); + spin_lock_irqsave(&hw->hw_lock, flags); __netif_rx_complete(dev); hw->intr_mask |= irqmask[skge->port]; skge_write32(hw, B0_IMSK, hw->intr_mask); skge_read32(hw, B0_IMSK); - spin_unlock_irq(&hw->hw_lock); + spin_unlock_irqrestore(&hw->hw_lock, flags); return 0; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index fb1d2c30c1b..822dd0b1313 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -569,8 +569,8 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) onoff = !onoff; + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - if (onoff) /* Turn off phy power saving */ reg1 &= ~phy_power[port]; @@ -579,6 +579,7 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_pci_read32(hw, PCI_DEV_REG1); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); udelay(100); } @@ -1511,6 +1512,13 @@ static int sky2_down(struct net_device *dev) imask &= ~portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); + /* + * Both ports share the NAPI poll on port 0, so if necessary undo the + * the disable that is done in dev_close. + */ + if (sky2->port == 0 && hw->ports > 1) + netif_poll_enable(dev); + sky2_gmac_reset(hw, port); /* Stop transmitter */ @@ -3658,6 +3666,6 @@ module_init(sky2_init_module); module_exit(sky2_cleanup_module); MODULE_DESCRIPTION("Marvell Yukon 2 Gigabit Ethernet driver"); -MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); +MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2c4343395a4..43af6143844 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -148,6 +148,8 @@ struct smc911x_local { int tx_throttle; spinlock_t lock; + struct net_device *netdev; + #ifdef SMC_USE_DMA /* DMA needs the physical address of the chip */ u_long physaddr; @@ -948,10 +950,11 @@ static void smc911x_phy_check_media(struct net_device *dev, int init) * of autonegotiation.) If the RPC ANEG bit is cleared, the selection * is controlled by the RPC SPEED and RPC DPLX bits. */ -static void smc911x_phy_configure(void *data) +static void smc911x_phy_configure(struct work_struct *work) { - struct net_device *dev = data; - struct smc911x_local *lp = netdev_priv(dev); + struct smc911x_local *lp = container_of(work, struct smc911x_local, + phy_configure); + struct net_device *dev = lp->netdev; unsigned long ioaddr = dev->base_addr; int phyaddr = lp->mii.phy_id; int my_phy_caps; /* My PHY capabilities */ @@ -965,11 +968,11 @@ static void smc911x_phy_configure(void *data) * We should not be called if phy_type is zero. */ if (lp->phy_type == 0) - goto smc911x_phy_configure_exit; + goto smc911x_phy_configure_exit_nolock; if (smc911x_phy_reset(dev, phyaddr)) { printk("%s: PHY reset timed out\n", dev->name); - goto smc911x_phy_configure_exit; + goto smc911x_phy_configure_exit_nolock; } spin_lock_irqsave(&lp->lock, flags); @@ -1038,6 +1041,7 @@ static void smc911x_phy_configure(void *data) smc911x_phy_configure_exit: spin_unlock_irqrestore(&lp->lock, flags); +smc911x_phy_configure_exit_nolock: lp->work_pending = 0; } @@ -1331,7 +1335,7 @@ smc911x_rx_dma_irq(int dma, void *data) static void smc911x_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - smc911x_interrupt(dev->irq, dev, NULL); + smc911x_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif @@ -1495,6 +1499,8 @@ static void smc911x_set_multicast_list(struct net_device *dev) static int smc911x_open(struct net_device *dev) { + struct smc911x_local *lp = netdev_priv(dev); + DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); /* @@ -1511,7 +1517,7 @@ smc911x_open(struct net_device *dev) smc911x_reset(dev); /* Configure the PHY, initialize the link state */ - smc911x_phy_configure(dev); + smc911x_phy_configure(&lp->phy_configure); /* Turn on Tx + Rx */ smc911x_enable(dev); @@ -2060,7 +2066,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) dev->poll_controller = smc911x_poll_controller; #endif - INIT_WORK(&lp->phy_configure, smc911x_phy_configure, dev); + INIT_WORK(&lp->phy_configure, smc911x_phy_configure); lp->mii.phy_id_mask = 0x1f; lp->mii.reg_num_mask = 0x1f; lp->mii.force_media = 0; @@ -2154,6 +2160,7 @@ static int smc911x_drv_probe(struct platform_device *pdev) { struct net_device *ndev; struct resource *res; + struct smc911x_local *lp; unsigned int *addr; int ret; @@ -2183,6 +2190,8 @@ static int smc911x_drv_probe(struct platform_device *pdev) ndev->dma = (unsigned char)-1; ndev->irq = platform_get_irq(pdev, 0); + lp = netdev_priv(ndev); + lp->netdev = ndev; addr = ioremap(res->start, SMC911X_IO_EXTENT); if (!addr) { @@ -2204,7 +2213,6 @@ out: } #ifdef SMC_USE_DMA else { - struct smc911x_local *lp = netdev_priv(ndev); lp->physaddr = res->start; lp->dev = &pdev->dev; } @@ -2275,7 +2283,7 @@ static int smc911x_drv_resume(struct platform_device *dev) smc911x_reset(ndev); smc911x_enable(ndev); if (lp->phy_type != 0) - smc911x_phy_configure(ndev); + smc911x_phy_configure(&lp->phy_configure); netif_device_attach(ndev); } } diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index ebb6aa39f9c..8ea2fc1b96c 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1925,6 +1925,8 @@ spider_net_stop(struct net_device *netdev) /* release chains */ spider_net_release_tx_chain(card, 1); + spider_net_free_rx_chain_contents(card); + spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 785e4a535f9..616be8d0fa8 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -90,7 +90,8 @@ #define ADVERTISE_MASK (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full | \ + SUPPORTED_Pause | SUPPORTED_Autoneg) #define DRV_NAME "sungem" #define DRV_VERSION "0.98" diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index 49800b25907..d21991ee88c 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -3,10 +3,9 @@ * * This file could be shared with other drivers. * - * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org) * * TODO: - * - Implement WOL * - Add support for PHYs that provide an IRQ line * - Eventually moved the entire polling state machine in * there (out of the eth driver), so that it can easily be @@ -152,6 +151,44 @@ static int bcm5221_suspend(struct mii_phy* phy) return 0; } +static int bcm5241_init(struct mii_phy* phy) +{ + u16 data; + + data = phy_read(phy, MII_BCM5221_TEST); + phy_write(phy, MII_BCM5221_TEST, + data | MII_BCM5221_TEST_ENABLE_SHADOWS); + + data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2); + phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2, + data | MII_BCM5221_SHDOW_AUX_STAT2_APD); + + data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); + phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, + data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR); + + data = phy_read(phy, MII_BCM5221_TEST); + phy_write(phy, MII_BCM5221_TEST, + data & ~MII_BCM5221_TEST_ENABLE_SHADOWS); + + return 0; +} + +static int bcm5241_suspend(struct mii_phy* phy) +{ + u16 data; + + data = phy_read(phy, MII_BCM5221_TEST); + phy_write(phy, MII_BCM5221_TEST, + data | MII_BCM5221_TEST_ENABLE_SHADOWS); + + data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); + phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, + data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR); + + return 0; +} + static int bcm5400_init(struct mii_phy* phy) { u16 data; @@ -373,6 +410,10 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; phy_write(phy, MII_ADVERTISE, adv); /* Setup 1000BT advertise */ @@ -436,12 +477,15 @@ static int bcm54xx_read_link(struct mii_phy *phy) val = phy_read(phy, MII_BCM5400_AUXSTATUS); link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); - phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF; + phy->duplex = phy_BCM5400_link_table[link_mode][0] ? + DUPLEX_FULL : DUPLEX_HALF; phy->speed = phy_BCM5400_link_table[link_mode][2] ? SPEED_1000 : - (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10); + (phy_BCM5400_link_table[link_mode][1] ? + SPEED_100 : SPEED_10); val = phy_read(phy, MII_LPA); - phy->pause = ((val & LPA_PAUSE) != 0); + phy->pause = (phy->duplex == DUPLEX_FULL) && + ((val & LPA_PAUSE) != 0); } /* On non-aneg, we assume what we put in BMCR is the speed, * though magic-aneg shouldn't prevent this case from occurring @@ -450,6 +494,28 @@ static int bcm54xx_read_link(struct mii_phy *phy) return 0; } +static int marvell88e1111_init(struct mii_phy* phy) +{ + u16 rev; + + /* magic init sequence for rev 0 */ + rev = phy_read(phy, MII_PHYSID2) & 0x000f; + if (rev == 0) { + phy_write(phy, 0x1d, 0x000a); + phy_write(phy, 0x1e, 0x0821); + + phy_write(phy, 0x1d, 0x0006); + phy_write(phy, 0x1e, 0x8600); + + phy_write(phy, 0x1d, 0x000b); + phy_write(phy, 0x1e, 0x0100); + + phy_write(phy, 0x1d, 0x0004); + phy_write(phy, 0x1e, 0x4850); + } + return 0; +} + static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) { u16 ctl, adv; @@ -471,6 +537,10 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; phy_write(phy, MII_ADVERTISE, adv); /* Setup 1000BT advertise & enable crossover detect @@ -549,7 +619,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd) static int marvell_read_link(struct mii_phy *phy) { - u16 status; + u16 status, pmask; if (phy->autoneg) { status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS); @@ -565,7 +635,9 @@ static int marvell_read_link(struct mii_phy *phy) phy->duplex = DUPLEX_FULL; else phy->duplex = DUPLEX_HALF; - phy->pause = 0; /* XXX Check against spec ! */ + pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE | + MII_M1011_PHY_SPEC_STATUS_RX_PAUSE; + phy->pause = (status & pmask) == pmask; } /* On non-aneg, we assume what we put in BMCR is the speed, * though magic-aneg shouldn't prevent this case from occurring @@ -595,6 +667,10 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; phy_write(phy, MII_ADVERTISE, adv); /* Start/Restart aneg */ @@ -666,7 +742,8 @@ static int genmii_read_link(struct mii_phy *phy) phy->speed = SPEED_100; else phy->speed = SPEED_10; - phy->pause = 0; + phy->pause = (phy->duplex == DUPLEX_FULL) && + ((lpa & LPA_PAUSE) != 0); } /* On non-aneg, we assume what we put in BMCR is the speed, * though magic-aneg shouldn't prevent this case from occurring @@ -676,11 +753,19 @@ static int genmii_read_link(struct mii_phy *phy) } -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) +#define MII_BASIC_FEATURES \ + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \ + SUPPORTED_Pause) + +/* On gigabit capable PHYs, we advertise Pause support but not asym pause + * support for now as I'm not sure it's supported and Darwin doesn't do + * it neither. --BenH. + */ +#define MII_GBIT_FEATURES \ + (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) /* Broadcom BCM 5201 */ static struct mii_phy_ops bcm5201_phy_ops = { @@ -720,6 +805,24 @@ static struct mii_phy_def bcm5221_phy_def = { .ops = &bcm5221_phy_ops }; +/* Broadcom BCM 5241 */ +static struct mii_phy_ops bcm5241_phy_ops = { + .suspend = bcm5241_suspend, + .init = bcm5241_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link, +}; +static struct mii_phy_def bcm5241_phy_def = { + .phy_id = 0x0143bc30, + .phy_id_mask = 0xfffffff0, + .name = "BCM5241", + .features = MII_BASIC_FEATURES, + .magic_aneg = 1, + .ops = &bcm5241_phy_ops +}; + /* Broadcom BCM 5400 */ static struct mii_phy_ops bcm5400_phy_ops = { .init = bcm5400_init, @@ -854,11 +957,8 @@ static struct mii_phy_def bcm5462V_phy_def = { .ops = &bcm5462V_phy_ops }; -/* Marvell 88E1101 (Apple seem to deal with 2 different revs, - * I masked out the 8 last bits to get both, but some specs - * would be useful here) --BenH. - */ -static struct mii_phy_ops marvell_phy_ops = { +/* Marvell 88E1101 amd 88E1111 */ +static struct mii_phy_ops marvell88e1101_phy_ops = { .suspend = generic_suspend, .setup_aneg = marvell_setup_aneg, .setup_forced = marvell_setup_forced, @@ -866,13 +966,41 @@ static struct mii_phy_ops marvell_phy_ops = { .read_link = marvell_read_link }; -static struct mii_phy_def marvell_phy_def = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E1101", +static struct mii_phy_ops marvell88e1111_phy_ops = { + .init = marvell88e1111_init, + .suspend = generic_suspend, + .setup_aneg = marvell_setup_aneg, + .setup_forced = marvell_setup_forced, + .poll_link = genmii_poll_link, + .read_link = marvell_read_link +}; + +/* two revs in darwin for the 88e1101 ... I could use a datasheet + * to get the proper names... + */ +static struct mii_phy_def marvell88e1101v1_phy_def = { + .phy_id = 0x01410c20, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1101v1", + .features = MII_GBIT_FEATURES, + .magic_aneg = 1, + .ops = &marvell88e1101_phy_ops +}; +static struct mii_phy_def marvell88e1101v2_phy_def = { + .phy_id = 0x01410c60, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1101v2", + .features = MII_GBIT_FEATURES, + .magic_aneg = 1, + .ops = &marvell88e1101_phy_ops +}; +static struct mii_phy_def marvell88e1111_phy_def = { + .phy_id = 0x01410cc0, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1111", .features = MII_GBIT_FEATURES, .magic_aneg = 1, - .ops = &marvell_phy_ops + .ops = &marvell88e1111_phy_ops }; /* Generic implementation for most 10/100 PHYs */ @@ -895,6 +1023,7 @@ static struct mii_phy_def genmii_phy_def = { static struct mii_phy_def* mii_phy_table[] = { &bcm5201_phy_def, &bcm5221_phy_def, + &bcm5241_phy_def, &bcm5400_phy_def, &bcm5401_phy_def, &bcm5411_phy_def, @@ -902,7 +1031,9 @@ static struct mii_phy_def* mii_phy_table[] = { &bcm5421k2_phy_def, &bcm5461_phy_def, &bcm5462V_phy_def, - &marvell_phy_def, + &marvell88e1101v1_phy_def, + &marvell88e1101v2_phy_def, + &marvell88e1111_phy_def, &genmii_phy_def, NULL }; diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h index 8ee1ca0471c..1d70ba6f9f1 100644 --- a/drivers/net/sungem_phy.h +++ b/drivers/net/sungem_phy.h @@ -30,7 +30,7 @@ struct mii_phy_def struct mii_phy { struct mii_phy_def* def; - int advertising; + u32 advertising; int mii_id; /* 1: autoneg enabled, 0: disabled */ @@ -85,6 +85,9 @@ extern int mii_phy_probe(struct mii_phy *phy, int mii_id); #define MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE 0x0001 #define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR 0x0004 +/* MII BCM5241 Additional registers */ +#define MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR 0x0008 + /* MII BCM5400 1000-BASET Control register */ #define MII_BCM5400_GB_CONTROL 0x09 #define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 @@ -115,5 +118,7 @@ extern int mii_phy_probe(struct mii_phy *phy, int mii_id); #define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 #define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 #define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 +#define MII_M1011_PHY_SPEC_STATUS_TX_PAUSE 0x0008 +#define MII_M1011_PHY_SPEC_STATUS_RX_PAUSE 0x0004 #endif /* __SUNGEM_PHY_H__ */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 571320ae87a..f4bf62c2a7a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.70" -#define DRV_MODULE_RELDATE "December 1, 2006" +#define DRV_MODULE_VERSION "3.72" +#define DRV_MODULE_RELDATE "January 8, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -959,6 +959,13 @@ static int tg3_phy_reset(struct tg3 *tp) u32 phy_status; int err; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u32 val; + + val = tr32(GRC_MISC_CFG); + tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ); + udelay(40); + } err = tg3_readphy(tp, MII_BMSR, &phy_status); err |= tg3_readphy(tp, MII_BMSR, &phy_status); if (err != 0) @@ -1008,7 +1015,12 @@ out: else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); - tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); + if (tp->tg3_flags2 & TG3_FLG2_PHY_ADJUST_TRIM) { + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); + tg3_writephy(tp, MII_TG3_TEST1, + MII_TG3_TEST1_TRIM_EN | 0x4); + } else + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); } /* Set Extended packet length bit (bit 14) on all chips that */ @@ -1170,7 +1182,15 @@ static void tg3_power_down_phy(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) return; - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + u32 val; + + tg3_bmcr_reset(tp); + val = tr32(GRC_MISC_CFG); + tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); + udelay(40); + return; + } else { tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); @@ -4426,7 +4446,7 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) * + tp->rx_std_buffers = kzalloc((sizeof(struct ring_info) * (TG3_RX_RING_SIZE + TG3_RX_JUMBO_RING_SIZE)) + (sizeof(struct tx_ring_info) * @@ -4435,13 +4455,6 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (!tp->rx_std_buffers) return -ENOMEM; - memset(tp->rx_std_buffers, 0, - (sizeof(struct ring_info) * - (TG3_RX_RING_SIZE + - TG3_RX_JUMBO_RING_SIZE)) + - (sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE)); - tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; tp->tx_buffers = (struct tx_ring_info *) &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; @@ -6988,6 +7001,8 @@ static int tg3_open(struct net_device *dev) struct tg3 *tp = netdev_priv(dev); int err; + netif_carrier_off(tp->dev); + tg3_full_lock(tp, 0); err = tg3_set_power_state(tp, PCI_D0); @@ -7981,6 +7996,10 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.duplex = cmd->duplex; } + tp->link_config.orig_speed = tp->link_config.speed; + tp->link_config.orig_duplex = tp->link_config.duplex; + tp->link_config.orig_autoneg = tp->link_config.autoneg; + if (netif_running(dev)) tg3_setup_phy(tp, 1); @@ -10789,9 +10808,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M) + tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM; + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; } @@ -11923,6 +11944,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, */ pci_save_state(tp->pdev); + pci_set_drvdata(pdev, dev); + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " @@ -11930,8 +11953,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ", dev->name, tp->board_part_number, @@ -11962,8 +11983,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (pdev->dma_mask == DMA_32BIT_MASK) ? 32 : (((u64) pdev->dma_mask == DMA_40BIT_MASK) ? 40 : 64)); - netif_carrier_off(tp->dev); - return 0; err_out_iounmap: diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index dfaf4ed127b..80f59ac7ec5 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1350,6 +1350,7 @@ #define GRC_MISC_CFG_BOARD_ID_5788 0x00010000 #define GRC_MISC_CFG_BOARD_ID_5788M 0x00018000 #define GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000 +#define GRC_MISC_CFG_EPHY_IDDQ 0x00200000 #define GRC_MISC_CFG_KEEP_GPHY_POWER 0x04000000 #define GRC_LOCAL_CTRL 0x00006808 #define GRC_LCLCTRL_INT_ACTIVE 0x00000001 @@ -1657,6 +1658,9 @@ #define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */ #define MII_TG3_EPHY_SHADOW_EN 0x80 +#define MII_TG3_TEST1 0x1e +#define MII_TG3_TEST1_TRIM_EN 0x0010 + /* There are two ways to manage the TX descriptors on the tigon3. * Either the descriptors are in host DMA'able memory, or they * exist only in the cards on-chip SRAM. All 16 send bds are under @@ -2255,6 +2259,7 @@ struct tg3 { #define TG3_FLG2_1SHOT_MSI 0x10000000 #define TG3_FLG2_PHY_JITTER_BUG 0x20000000 #define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 +#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 8243150f5b0..7e4b23c7c1b 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -29,6 +29,7 @@ #include <linux/fsl_devices.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/workqueue.h> #include <asm/of_platform.h> #include <asm/uaccess.h> @@ -472,7 +473,7 @@ static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont) kfree(enet_addr_cont); } -static int set_mac_addr(__be16 __iomem *reg, u8 *mac) +static void set_mac_addr(__be16 __iomem *reg, u8 *mac) { out_be16(®[0], ((u16)mac[5] << 8) | mac[4]); out_be16(®[1], ((u16)mac[3] << 8) | mac[2]); @@ -3920,10 +3921,11 @@ static irqreturn_t phy_interrupt(int irq, void *dev_id) } /* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void ugeth_phy_change(void *data) +static void ugeth_phy_change(struct work_struct *work) { - struct net_device *dev = (struct net_device *)data; - struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = + container_of(work, struct ucc_geth_private, tq); + struct net_device *dev = ugeth->dev; struct ucc_geth *ug_regs; int result = 0; @@ -4080,7 +4082,7 @@ static int ucc_geth_open(struct net_device *dev) #endif /* CONFIG_UGETH_NAPI */ /* Set up the PHY change work queue */ - INIT_WORK(&ugeth->tq, ugeth_phy_change, dev); + INIT_WORK(&ugeth->tq, ugeth_phy_change); init_timer(&ugeth->phy_info_timer); ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c index 5360ec05eaa..3c86592ce03 100644 --- a/drivers/net/ucc_geth_phy.c +++ b/drivers/net/ucc_geth_phy.c @@ -68,8 +68,31 @@ static int gbit_config_aneg(struct ugeth_mii_info *mii_info); static int genmii_config_aneg(struct ugeth_mii_info *mii_info); static int genmii_update_link(struct ugeth_mii_info *mii_info); static int genmii_read_status(struct ugeth_mii_info *mii_info); -u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum); -void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val); + +static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum) +{ + u16 retval; + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); + + return retval; +} + +static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) +{ + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); +} /* Write value to the PHY for this device to the register at regnum, */ /* waiting until the write is done before it returns. All PHY */ @@ -184,7 +207,7 @@ static void config_genmii_advert(struct ugeth_mii_info *mii_info) advertise = mii_info->advertising; /* Setup standard advertisement */ - adv = phy_read(mii_info, MII_ADVERTISE); + adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (advertise & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; @@ -194,7 +217,7 @@ static void config_genmii_advert(struct ugeth_mii_info *mii_info) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; - phy_write(mii_info, MII_ADVERTISE, adv); + ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv); } static void genmii_setup_forced(struct ugeth_mii_info *mii_info) @@ -204,7 +227,7 @@ static void genmii_setup_forced(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); - ctrl = phy_read(mii_info, MII_BMCR); + ctrl = ucc_geth_phy_read(mii_info, MII_BMCR); ctrl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); @@ -234,7 +257,7 @@ static void genmii_setup_forced(struct ugeth_mii_info *mii_info) break; } - phy_write(mii_info, MII_BMCR, ctrl); + ucc_geth_phy_write(mii_info, MII_BMCR, ctrl); } /* Enable and Restart Autonegotiation */ @@ -244,9 +267,9 @@ static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); - ctl = phy_read(mii_info, MII_BMCR); + ctl = ucc_geth_phy_read(mii_info, MII_BMCR); ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(mii_info, MII_BMCR, ctl); + ucc_geth_phy_write(mii_info, MII_BMCR, ctl); } static int gbit_config_aneg(struct ugeth_mii_info *mii_info) @@ -261,14 +284,14 @@ static int gbit_config_aneg(struct ugeth_mii_info *mii_info) config_genmii_advert(mii_info); advertise = mii_info->advertising; - adv = phy_read(mii_info, MII_1000BASETCONTROL); + adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL); adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | MII_1000BASETCONTROL_HALFDUPLEXCAP); if (advertise & SUPPORTED_1000baseT_Half) adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; if (advertise & SUPPORTED_1000baseT_Full) adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; - phy_write(mii_info, MII_1000BASETCONTROL, adv); + ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv); /* Start/Restart aneg */ genmii_restart_aneg(mii_info); @@ -298,10 +321,10 @@ static int genmii_update_link(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); /* Do a fake read */ - phy_read(mii_info, MII_BMSR); + ucc_geth_phy_read(mii_info, MII_BMSR); /* Read link and autonegotiation status */ - status = phy_read(mii_info, MII_BMSR); + status = ucc_geth_phy_read(mii_info, MII_BMSR); if ((status & BMSR_LSTATUS) == 0) mii_info->link = 0; else @@ -329,7 +352,7 @@ static int genmii_read_status(struct ugeth_mii_info *mii_info) return err; if (mii_info->autoneg) { - status = phy_read(mii_info, MII_LPA); + status = ucc_geth_phy_read(mii_info, MII_LPA); if (status & (LPA_10FULL | LPA_100FULL)) mii_info->duplex = DUPLEX_FULL; @@ -352,9 +375,9 @@ static int marvell_init(struct ugeth_mii_info *mii_info) { ugphy_vdbg("%s: IN", __FUNCTION__); - phy_write(mii_info, 0x14, 0x0cd2); - phy_write(mii_info, MII_BMCR, - phy_read(mii_info, MII_BMCR) | BMCR_RESET); + ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); + ucc_geth_phy_write(mii_info, MII_BMCR, + ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); msleep(4000); return 0; @@ -367,13 +390,13 @@ static int marvell_config_aneg(struct ugeth_mii_info *mii_info) /* The Marvell PHY has an errata which requires * that certain registers get written in order * to restart autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_RESET); + ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET); - phy_write(mii_info, 0x1d, 0x1f); - phy_write(mii_info, 0x1e, 0x200c); - phy_write(mii_info, 0x1d, 0x5); - phy_write(mii_info, 0x1e, 0); - phy_write(mii_info, 0x1e, 0x100); + ucc_geth_phy_write(mii_info, 0x1d, 0x1f); + ucc_geth_phy_write(mii_info, 0x1e, 0x200c); + ucc_geth_phy_write(mii_info, 0x1d, 0x5); + ucc_geth_phy_write(mii_info, 0x1e, 0); + ucc_geth_phy_write(mii_info, 0x1e, 0x100); gbit_config_aneg(mii_info); @@ -398,7 +421,7 @@ static int marvell_read_status(struct ugeth_mii_info *mii_info) * are as set */ if (mii_info->autoneg && mii_info->link) { int speed; - status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); + status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); /* Get the duplexity */ if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) @@ -430,7 +453,7 @@ static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); /* Clear the interrupts by reading the reg */ - phy_read(mii_info, MII_M1011_IEVENT); + ucc_geth_phy_read(mii_info, MII_M1011_IEVENT); return 0; } @@ -440,9 +463,9 @@ static int marvell_config_intr(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); return 0; } @@ -451,9 +474,9 @@ static int cis820x_init(struct ugeth_mii_info *mii_info) { ugphy_vdbg("%s: IN", __FUNCTION__); - phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, + ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, MII_CIS8201_AUXCONSTAT_INIT); - phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); + ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); return 0; } @@ -477,7 +500,7 @@ static int cis820x_read_status(struct ugeth_mii_info *mii_info) if (mii_info->autoneg && mii_info->link) { int speed; - status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); + status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) mii_info->duplex = DUPLEX_FULL; else @@ -505,7 +528,7 @@ static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) { ugphy_vdbg("%s: IN", __FUNCTION__); - phy_read(mii_info, MII_CIS8201_ISTAT); + ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT); return 0; } @@ -515,9 +538,9 @@ static int cis820x_config_intr(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); + ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); else - phy_write(mii_info, MII_CIS8201_IMASK, 0); + ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0); return 0; } @@ -541,7 +564,7 @@ static int dm9161_read_status(struct ugeth_mii_info *mii_info) /* If we aren't autonegotiating, assume speeds * are as set */ if (mii_info->autoneg && mii_info->link) { - status = phy_read(mii_info, MII_DM9161_SCSR); + status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR); if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) mii_info->speed = SPEED_100; else @@ -572,7 +595,7 @@ static void dm9161_timer(unsigned long data) { struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; struct dm9161_private *priv = mii_info->priv; - u16 status = phy_read(mii_info, MII_BMSR); + u16 status = ucc_geth_phy_read(mii_info, MII_BMSR); ugphy_vdbg("%s: IN", __FUNCTION__); @@ -599,11 +622,11 @@ static int dm9161_init(struct ugeth_mii_info *mii_info) /* Reset is not done yet */ priv->resetdone = 0; - phy_write(mii_info, MII_BMCR, - phy_read(mii_info, MII_BMCR) | BMCR_RESET); + ucc_geth_phy_write(mii_info, MII_BMCR, + ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); - phy_write(mii_info, MII_BMCR, - phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); + ucc_geth_phy_write(mii_info, MII_BMCR, + ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); config_genmii_advert(mii_info); /* Start/Restart aneg */ @@ -634,7 +657,7 @@ static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); /* Clear the interrupts by reading the reg */ - phy_read(mii_info, MII_DM9161_INTR); + ucc_geth_phy_read(mii_info, MII_DM9161_INTR); return 0; @@ -645,9 +668,9 @@ static int dm9161_config_intr(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); + ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); else - phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); return 0; } @@ -718,31 +741,6 @@ static struct phy_info *phy_info[] = { NULL }; -u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum) -{ - u16 retval; - unsigned long flags; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); - - return retval; -} - -void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) -{ - unsigned long flags; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); -} - /* Use the PHY ID registers to determine what type of PHY is attached * to device dev. return a struct phy_info structure describing that PHY */ @@ -757,11 +755,11 @@ struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = phy_read(mii_info, MII_PHYSID1); + phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1); phy_ID = (phy_reg & 0xffff) << 16; /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = phy_read(mii_info, MII_PHYSID2); + phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2); phy_ID |= (phy_reg & 0xffff); /* loop through all the known PHY types, and find one that */ diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 4587f23f4e4..8e5d82051bd 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -265,15 +265,19 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); static int velocity_suspend(struct pci_dev *pdev, pm_message_t state); static int velocity_resume(struct pci_dev *pdev); +static DEFINE_SPINLOCK(velocity_dev_list_lock); +static LIST_HEAD(velocity_dev_list); + +#endif + +#if defined(CONFIG_PM) && defined(CONFIG_INET) + static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); static struct notifier_block velocity_inetaddr_notifier = { .notifier_call = velocity_netdev_event, }; -static DEFINE_SPINLOCK(velocity_dev_list_lock); -static LIST_HEAD(velocity_dev_list); - static void velocity_register_notifier(void) { register_inetaddr_notifier(&velocity_inetaddr_notifier); @@ -284,12 +288,12 @@ static void velocity_unregister_notifier(void) unregister_inetaddr_notifier(&velocity_inetaddr_notifier); } -#else /* CONFIG_PM */ +#else #define velocity_register_notifier() do {} while (0) #define velocity_unregister_notifier() do {} while (0) -#endif /* !CONFIG_PM */ +#endif /* * Internal board variants. At the moment we have only one @@ -3292,6 +3296,8 @@ static int velocity_resume(struct pci_dev *pdev) return 0; } +#ifdef CONFIG_INET + static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) { struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; @@ -3312,4 +3318,6 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi } return NOTIFY_DONE; } + +#endif #endif diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 2ec2e5afce6..91b752e3d07 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2701,8 +2701,8 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); /* extract core_id, core_rev, core_vendor */ - core_id = (sb_id_hi & 0xFFF0) >> 4; - core_rev = (sb_id_hi & 0xF); + core_id = (sb_id_hi & 0x8FF0) >> 4; + core_rev = ((sb_id_hi & 0xF) | ((sb_id_hi & 0x7000) >> 8)); core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x\n", @@ -2873,7 +2873,10 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; - sbimconfiglow |= 0x32; + if (bcm->bustype == BCM43xx_BUSTYPE_PCI) + sbimconfiglow |= 0x32; + else + sbimconfiglow |= 0x53; bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); } @@ -3077,7 +3080,7 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, if (err) goto out; - if (bcm->current_core->rev < 6 || + if (bcm->current_core->rev < 6 && bcm->current_core->id == BCM43xx_COREID_PCI) { value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); value |= (1 << backplane_flag_nr); diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 0e94fbbf7a9..b85857a8487 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -2664,7 +2664,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) break; } #endif - if (stats.len < sizeof(u->rx_data.header)) + if (stats.len < sizeof(struct ieee80211_hdr_3addr)) break; switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) { case IEEE80211_FTYPE_MGMT: diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 644b4741ef7..a009ab51771 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -406,7 +406,6 @@ static int netwave_probe(struct pcmcia_device *link) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; /* Netwave private struct init. link/dev/node already taken care of, * other stuff zero'd - Jean II */ diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88e10c9bc4a..47b2ccb6a63 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -331,7 +331,6 @@ static int ray_probe(struct pcmcia_device *p_dev) p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; p_dev->conf.ConfigIndex = 1; - p_dev->conf.Present = PRESENT_OPTION; p_dev->priv = dev; p_dev->irq.Instance = dev; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 583e0d655a9..c250f08c8dd 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1928,7 +1928,6 @@ static int wl3501_probe(struct pcmcia_device *p_dev) p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; p_dev->conf.ConfigIndex = 1; - p_dev->conf.Present = PRESENT_OPTION; dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 00ca704ece3..a08524191b5 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -41,6 +41,8 @@ static void housekeeping_disable(struct zd_mac *mac); static void set_multicast_hash_handler(struct work_struct *work); +static void do_rx(unsigned long mac_ptr); + int zd_mac_init(struct zd_mac *mac, struct net_device *netdev, struct usb_interface *intf) @@ -53,6 +55,10 @@ int zd_mac_init(struct zd_mac *mac, INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); + skb_queue_head_init(&mac->rx_queue); + tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac); + tasklet_disable(&mac->rx_tasklet); + ieee_init(ieee); softmac_init(ieee80211_priv(netdev)); zd_chip_init(&mac->chip, netdev, intf); @@ -140,6 +146,8 @@ out: void zd_mac_clear(struct zd_mac *mac) { flush_workqueue(zd_workqueue); + skb_queue_purge(&mac->rx_queue); + tasklet_kill(&mac->rx_tasklet); zd_chip_clear(&mac->chip); ZD_ASSERT(!spin_is_locked(&mac->lock)); ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); @@ -168,6 +176,8 @@ int zd_mac_open(struct net_device *netdev) struct zd_chip *chip = &mac->chip; int r; + tasklet_enable(&mac->rx_tasklet); + r = zd_chip_enable_int(chip); if (r < 0) goto out; @@ -218,6 +228,8 @@ int zd_mac_stop(struct net_device *netdev) */ zd_chip_disable_rx(chip); + skb_queue_purge(&mac->rx_queue); + tasklet_disable(&mac->rx_tasklet); housekeeping_disable(mac); ieee80211softmac_stop(netdev); @@ -470,13 +482,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes) if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) { /* Set RTS rate to highest available basic rate */ - u8 rate = ieee80211softmac_highest_supported_rate(softmac, + u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac, &bssinfo->supported_rates, 1); - rate = rate_to_zd_rate(rate); + hi_rate = rate_to_zd_rate(hi_rate); spin_lock_irqsave(&mac->lock, flags); - if (rate != mac->rts_rate) { - mac->rts_rate = rate; + if (hi_rate != mac->rts_rate) { + mac->rts_rate = hi_rate; need_set_rts_cts = 1; } spin_unlock_irqrestore(&mac->lock, flags); @@ -1072,43 +1084,75 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats, return 0; } -int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length) +static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) { int r; struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); struct ieee80211_rx_stats stats; const struct rx_status *status; - struct sk_buff *skb; - if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + - IEEE80211_FCS_LEN + sizeof(struct rx_status)) - return -EINVAL; + if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + + IEEE80211_FCS_LEN + sizeof(struct rx_status)) + { + dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n", + skb->len); + goto free_skb; + } - r = fill_rx_stats(&stats, &status, mac, buffer, length); - if (r) - return r; + r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); + if (r) { + /* Only packets with rx errors are included here. */ + goto free_skb; + } - length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+ - sizeof(struct rx_status); - buffer += ZD_PLCP_HEADER_SIZE; + __skb_pull(skb, ZD_PLCP_HEADER_SIZE); + __skb_trim(skb, skb->len - + (IEEE80211_FCS_LEN + sizeof(struct rx_status))); - update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi); + update_qual_rssi(mac, skb->data, skb->len, stats.signal, + status->signal_strength); - r = filter_rx(ieee, buffer, length, &stats); - if (r <= 0) - return r; + r = filter_rx(ieee, skb->data, skb->len, &stats); + if (r <= 0) { + if (r < 0) + dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); + goto free_skb; + } - skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); - if (!skb) - return -ENOMEM; if (ieee->iw_mode == IW_MODE_MONITOR) - fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac, + fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac, &stats, status); - memcpy(skb_put(skb, length), buffer, length); r = ieee80211_rx(ieee, skb, &stats); - if (!r) - dev_kfree_skb_any(skb); + if (r) + return; +free_skb: + /* We are always in a soft irq. */ + dev_kfree_skb(skb); +} + +static void do_rx(unsigned long mac_ptr) +{ + struct zd_mac *mac = (struct zd_mac *)mac_ptr; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&mac->rx_queue)) != NULL) + zd_mac_rx(mac, skb); +} + +int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); + if (!skb) { + dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); + return -ENOMEM; + } + skb_reserve(skb, sizeof(struct zd_rt_hdr)); + memcpy(__skb_put(skb, length), buffer, length); + skb_queue_tail(&mac->rx_queue, skb); + tasklet_schedule(&mac->rx_tasklet); return 0; } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index f0cf05dc7d3..faf4c7828d4 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -138,6 +138,9 @@ struct zd_mac { struct delayed_work set_rts_cts_work; struct delayed_work set_basic_rates_work; + struct tasklet_struct rx_tasklet; + struct sk_buff_head rx_queue; + unsigned int stats_count; u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; @@ -193,7 +196,7 @@ int zd_mac_stop(struct net_device *netdev); int zd_mac_set_mac_address(struct net_device *dev, void *p); void zd_mac_set_multicast_list(struct net_device *netdev); -int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length); +int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length); int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain); u8 zd_mac_get_regdomain(struct zd_mac *zd_mac); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index aa782e88754..605e96e7405 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -598,13 +598,13 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, n = l+k; if (n > length) return; - zd_mac_rx(mac, buffer+l, k); + zd_mac_rx_irq(mac, buffer+l, k); if (i >= 2) return; l = (n+3) & ~3; } } else { - zd_mac_rx(mac, buffer, length); + zd_mac_rx_irq(mac, buffer, length); } } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index f1dd81a1d59..3cfb0a3575e 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -19,7 +19,7 @@ config PCI_MSI config PCI_MULTITHREAD_PROBE bool "PCI Multi-threaded probe (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL && BROKEN help Say Y here if you want the PCI core to spawn a new thread for every PCI device that is probed. This can cause a huge diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 0b9d0db1590..bd1faebf61a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1682,7 +1682,7 @@ int __init acpiphp_glue_init(void) * * This function frees all data allocated in acpiphp_glue_init() */ -void __exit acpiphp_glue_exit(void) +void acpiphp_glue_exit(void) { acpi_pci_unregister_driver(&acpi_pci_hp_driver); } diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index bd40aee10e1..7f03881a8b6 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -319,13 +319,12 @@ static int ibm_get_table_from_acpi(char **bufp) if (bufp == NULL) goto read_table_done; - lbuf = kmalloc(size, GFP_KERNEL); + lbuf = kzalloc(size, GFP_KERNEL); dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n", __FUNCTION__, package->package.count, size, lbuf); if (lbuf) { *bufp = lbuf; - memset(lbuf, 0, size); } else { size = -ENOMEM; goto read_table_done; diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index b771196a654..3009193f005 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -47,21 +47,11 @@ static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf) return retval; } -static struct hotplug_slot_attribute hotplug_slot_attr_location = { +static struct hotplug_slot_attribute php_attr_location = { .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO}, .show = location_read_file, }; -static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot) -{ - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr); -} - -static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot) -{ - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr); -} - /* free up the memory used by a slot */ static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) { @@ -145,7 +135,7 @@ int rpaphp_deregister_slot(struct slot *slot) list_del(&slot->rpaphp_slot_list); /* remove "phy_location" file */ - rpaphp_sysfs_remove_attr_location(php_slot); + sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr); retval = pci_hp_deregister(php_slot); if (retval) @@ -160,36 +150,45 @@ EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); int rpaphp_register_slot(struct slot *slot) { + struct hotplug_slot *php_slot = slot->hotplug_slot; int retval; dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", __FUNCTION__, slot->dn->full_name, slot->index, slot->name, slot->power_domain, slot->type); + /* should not try to register the same slot twice */ - if (is_registered(slot)) { /* should't be here */ + if (is_registered(slot)) { err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); - rpaphp_release_slot(slot->hotplug_slot); - return -EAGAIN; + retval = -EAGAIN; + goto register_fail; } - retval = pci_hp_register(slot->hotplug_slot); + + retval = pci_hp_register(php_slot); if (retval) { err("pci_hp_register failed with error %d\n", retval); - rpaphp_release_slot(slot->hotplug_slot); - return retval; + goto register_fail; } - - /* create "phy_locatoin" file */ - rpaphp_sysfs_add_attr_location(slot->hotplug_slot); - /* add slot to our internal list */ - dbg("%s adding slot[%s] to rpaphp_slot_list\n", - __FUNCTION__, slot->name); + /* create "phy_location" file */ + retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr); + if (retval) { + err("sysfs_create_file failed with error %d\n", retval); + goto sysfs_fail; + } + /* add slot to our internal list */ list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); info("Slot [%s](PCI location=%s) registered\n", slot->name, slot->location); num_slots++; return 0; + +sysfs_fail: + pci_hp_deregister(php_slot); +register_fail: + rpaphp_release_slot(php_slot); + return retval; } int rpaphp_get_power_status(struct slot *slot, u8 * value) diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 50757695844..3ca6a4f574b 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -47,11 +47,17 @@ extern int shpchp_poll_time; extern int shpchp_debug; extern struct workqueue_struct *shpchp_wq; -/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ -#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) +#define dbg(format, arg...) \ + do { \ + if (shpchp_debug) \ + printk("%s: " format, MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) #define SLOT_NAME_SIZE 10 struct slot { @@ -83,34 +89,27 @@ struct event_info { struct controller { struct mutex crit_sect; /* critical section mutex */ struct mutex cmd_lock; /* command lock */ - struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; struct list_head slot_list; struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ - u8 bus; - u8 device; - u8 function; u8 slot_device_offset; - u8 add_support; u32 pcix_misc2_reg; /* for amd pogo errata */ - enum pci_bus_speed speed; u32 first_slot; /* First physical slot number */ - u8 slot_bus; /* Bus where the slots handled by this controller sit */ u32 cap_offset; unsigned long mmio_base; unsigned long mmio_size; + void __iomem *creg; + struct timer_list poll_timer; }; - /* Define AMD SHPC ID */ #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 #define PCI_DEVICE_ID_AMD_POGO_7458 0x7458 /* AMD PCIX bridge registers */ - #define PCIX_MEM_BASE_LIMIT_OFFSET 0x1C #define PCIX_MISCII_OFFSET 0x48 #define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80 @@ -145,8 +144,6 @@ struct controller { #define POWERON_STATE 3 #define POWEROFF_STATE 4 -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - /* Error messages */ #define INTERLOCK_OPEN 0x00000002 #define ADD_NOT_SUPPORTED 0x00000003 @@ -158,50 +155,32 @@ struct controller { #define WRONG_BUS_FREQUENCY 0x0000000D #define POWER_FAILURE 0x0000000E -#define REMOVE_NOT_SUPPORTED 0x00000003 - -#define DISABLE_CARD 1 - -/* - * error Messages - */ -#define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_button_on "PCI slot #%s - powering on due to button press.\n" -#define msg_button_off "PCI slot #%s - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" - -/* sysfs functions for the hotplug controller info */ extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl); - -extern int shpchp_sysfs_enable_slot(struct slot *slot); -extern int shpchp_sysfs_disable_slot(struct slot *slot); - -extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id); -extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); -extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); -extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); - -/* pci functions */ -extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int shpchp_configure_device(struct slot *p_slot); -extern int shpchp_unconfigure_device(struct slot *p_slot); -extern void shpchp_remove_ctrl_files(struct controller *ctrl); -extern void cleanup_slots(struct controller *ctrl); -extern void queue_pushbutton_work(struct work_struct *work); - +extern void shpchp_remove_ctrl_files(struct controller *ctrl); +extern int shpchp_sysfs_enable_slot(struct slot *slot); +extern int shpchp_sysfs_disable_slot(struct slot *slot); +extern u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl); +extern u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl); +extern u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl); +extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl); +extern int shpchp_configure_device(struct slot *p_slot); +extern int shpchp_unconfigure_device(struct slot *p_slot); +extern void cleanup_slots(struct controller *ctrl); +extern void queue_pushbutton_work(struct work_struct *work); +extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); #ifdef CONFIG_ACPI static inline int get_hp_params_from_firmware(struct pci_dev *dev, - struct hotplug_params *hpp) + struct hotplug_params *hpp) { if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp))) return -ENODEV; return 0; } -#define get_hp_hw_control_from_firmware(pdev) \ - do { \ - if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \ - acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev))); \ +#define get_hp_hw_control_from_firmware(pdev) \ + do { \ + if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \ + acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev)));\ } while (0) #else #define get_hp_params_from_firmware(dev, hpp) (-ENODEV) @@ -222,108 +201,40 @@ struct ctrl_reg { volatile u32 serr_loc; volatile u32 serr_intr_enable; volatile u32 slot1; - volatile u32 slot2; - volatile u32 slot3; - volatile u32 slot4; - volatile u32 slot5; - volatile u32 slot6; - volatile u32 slot7; - volatile u32 slot8; - volatile u32 slot9; - volatile u32 slot10; - volatile u32 slot11; - volatile u32 slot12; } __attribute__ ((packed)); /* offsets to the controller registers based on the above structure layout */ enum ctrl_offsets { - BASE_OFFSET = offsetof(struct ctrl_reg, base_offset), - SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1), - SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2), - SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config), - SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config), - MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl), - PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface), - CMD = offsetof(struct ctrl_reg, cmd), - CMD_STATUS = offsetof(struct ctrl_reg, cmd_status), - INTR_LOC = offsetof(struct ctrl_reg, intr_loc), - SERR_LOC = offsetof(struct ctrl_reg, serr_loc), - SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable), - SLOT1 = offsetof(struct ctrl_reg, slot1), - SLOT2 = offsetof(struct ctrl_reg, slot2), - SLOT3 = offsetof(struct ctrl_reg, slot3), - SLOT4 = offsetof(struct ctrl_reg, slot4), - SLOT5 = offsetof(struct ctrl_reg, slot5), - SLOT6 = offsetof(struct ctrl_reg, slot6), - SLOT7 = offsetof(struct ctrl_reg, slot7), - SLOT8 = offsetof(struct ctrl_reg, slot8), - SLOT9 = offsetof(struct ctrl_reg, slot9), - SLOT10 = offsetof(struct ctrl_reg, slot10), - SLOT11 = offsetof(struct ctrl_reg, slot11), - SLOT12 = offsetof(struct ctrl_reg, slot12), -}; -typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id); -struct php_ctlr_state_s { - struct php_ctlr_state_s *pnext; - struct pci_dev *pci_dev; - unsigned int irq; - unsigned long flags; /* spinlock's */ - u32 slot_device_offset; - u32 num_slots; - struct timer_list int_poll_timer; /* Added for poll event */ - php_intr_callback_t attention_button_callback; - php_intr_callback_t switch_change_callback; - php_intr_callback_t presence_change_callback; - php_intr_callback_t power_fault_callback; - void *callback_instance_id; - void __iomem *creg; /* Ptr to controller register space */ + BASE_OFFSET = offsetof(struct ctrl_reg, base_offset), + SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1), + SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2), + SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config), + SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config), + MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl), + PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface), + CMD = offsetof(struct ctrl_reg, cmd), + CMD_STATUS = offsetof(struct ctrl_reg, cmd_status), + INTR_LOC = offsetof(struct ctrl_reg, intr_loc), + SERR_LOC = offsetof(struct ctrl_reg, serr_loc), + SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable), + SLOT1 = offsetof(struct ctrl_reg, slot1), }; -/* Inline functions */ - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check (slot, function)) - return NULL; - return slot; + return hotplug_slot->private; } -static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device) +static inline struct slot *shpchp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot; - if (!ctrl) - return NULL; - list_for_each_entry(slot, &ctrl->slot_list, slot_list) { if (slot->device == device) return slot; } err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device); - return NULL; } @@ -400,44 +311,27 @@ static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot) pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp); } -enum php_ctlr_type { - PCI, - ISA, - ACPI -}; - -int shpc_init( struct controller *ctrl, struct pci_dev *pdev); - -int shpc_get_ctlr_slot_config( struct controller *ctrl, - int *num_ctlr_slots, - int *first_device_num, - int *physical_slot_num, - int *updown, - int *flags); - struct hpc_ops { - int (*power_on_slot ) (struct slot *slot); - int (*slot_enable ) (struct slot *slot); - int (*slot_disable ) (struct slot *slot); - int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed); - int (*get_power_status) (struct slot *slot, u8 *status); - int (*get_attention_status) (struct slot *slot, u8 *status); - int (*set_attention_status) (struct slot *slot, u8 status); - int (*get_latch_status) (struct slot *slot, u8 *status); - int (*get_adapter_status) (struct slot *slot, u8 *status); - - int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_adapter_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_mode1_ECC_cap) (struct slot *slot, u8 *mode); - int (*get_prog_int) (struct slot *slot, u8 *prog_int); - - int (*query_power_fault) (struct slot *slot); - void (*green_led_on) (struct slot *slot); - void (*green_led_off) (struct slot *slot); - void (*green_led_blink) (struct slot *slot); - void (*release_ctlr) (struct controller *ctrl); - int (*check_cmd_status) (struct controller *ctrl); + int (*power_on_slot)(struct slot *slot); + int (*slot_enable)(struct slot *slot); + int (*slot_disable)(struct slot *slot); + int (*set_bus_speed_mode)(struct slot *slot, enum pci_bus_speed speed); + int (*get_power_status)(struct slot *slot, u8 *status); + int (*get_attention_status)(struct slot *slot, u8 *status); + int (*set_attention_status)(struct slot *slot, u8 status); + int (*get_latch_status)(struct slot *slot, u8 *status); + int (*get_adapter_status)(struct slot *slot, u8 *status); + int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_adapter_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_mode1_ECC_cap)(struct slot *slot, u8 *mode); + int (*get_prog_int)(struct slot *slot, u8 *prog_int); + int (*query_power_fault)(struct slot *slot); + void (*green_led_on)(struct slot *slot); + void (*green_led_off)(struct slot *slot); + void (*green_led_blink)(struct slot *slot); + void (*release_ctlr)(struct controller *ctrl); + int (*check_cmd_status)(struct controller *ctrl); }; #endif /* _SHPCHP_H */ diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 4eac85b3d90..590cd3cbe01 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -104,23 +104,6 @@ static void make_slot_name(struct slot *slot) slot->bus, slot->number); } - - - -static int -shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, - u8 busnum, u8 devnum) -{ - int offset = devnum - ctrl->slot_device_offset; - - dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, - ctrl->slot_num_inc, offset); - *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset); - return 0; -} - - - static int init_slots(struct controller *ctrl) { struct slot *slot; @@ -128,7 +111,6 @@ static int init_slots(struct controller *ctrl) struct hotplug_slot_info *info; int retval = -ENOMEM; int i; - u32 sun; for (i = 0; i < ctrl->num_slots; i++) { slot = kzalloc(sizeof(*slot), GFP_KERNEL); @@ -149,16 +131,11 @@ static int init_slots(struct controller *ctrl) slot->hp_slot = i; slot->ctrl = ctrl; - slot->bus = ctrl->slot_bus; + slot->bus = ctrl->pci_dev->subordinate->number; slot->device = ctrl->slot_device_offset + i; slot->hpc_ops = ctrl->hpc_ops; + slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); mutex_init(&slot->lock); - - if (shpchprm_get_physical_slot_number(ctrl, &sun, - slot->bus, slot->device)) - goto error_info; - - slot->number = sun; INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work); /* register this slot with the hotplug pci core */ @@ -211,42 +188,12 @@ void cleanup_slots(struct controller *ctrl) } } -static int get_ctlr_slot_config(struct controller *ctrl) -{ - int num_ctlr_slots; - int first_device_num; - int physical_slot_num; - int updown; - int rc; - int flags; - - rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, - &first_device_num, &physical_slot_num, - &updown, &flags); - if (rc) { - err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", - __FUNCTION__, ctrl->bus, ctrl->device); - return -1; - } - - ctrl->num_slots = num_ctlr_slots; - ctrl->slot_device_offset = first_device_num; - ctrl->first_slot = physical_slot_num; - ctrl->slot_num_inc = updown; /* either -1 or 1 */ - - dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d " - "(%x:%x)\n", __FUNCTION__, num_ctlr_slots, first_device_num, - physical_slot_num, updown, ctrl->bus, ctrl->device); - - return 0; -} - /* * set_attention_status - Turns the Amber LED for a slot on, off or blink */ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -258,7 +205,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) static int enable_slot (struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -267,7 +214,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot) static int disable_slot (struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -276,7 +223,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot) static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -290,7 +237,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -304,7 +251,7 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -318,7 +265,7 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -332,7 +279,7 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) static int get_address (struct hotplug_slot *hotplug_slot, u32 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -344,7 +291,7 @@ static int get_address (struct hotplug_slot *hotplug_slot, u32 *value) static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -358,7 +305,7 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + struct slot *slot = get_slot(hotplug_slot); int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); @@ -385,9 +332,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc; struct controller *ctrl; - struct slot *t_slot; - int first_device_num; /* first PCI device number */ - int num_ctlr_slots; /* number of slots implemented */ if (!is_shpc_capable(pdev)) return -ENODEV; @@ -408,47 +352,13 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, ctrl); - ctrl->bus = pdev->bus->number; - ctrl->slot_bus = pdev->subordinate->number; - ctrl->device = PCI_SLOT(pdev->devfn); - ctrl->function = PCI_FUNC(pdev->devfn); - - dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", - ctrl->bus, ctrl->device, ctrl->function, pdev->irq); - - /* - * Save configuration headers for this and subordinate PCI buses - */ - rc = get_ctlr_slot_config(ctrl); - if (rc) { - err(msg_initialization_err, rc); - goto err_out_release_ctlr; - } - first_device_num = ctrl->slot_device_offset; - num_ctlr_slots = ctrl->num_slots; - - ctrl->add_support = 1; - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { - err(msg_initialization_err, 6); + err("%s: slot initialization failed\n", SHPC_MODULE_NAME); goto err_out_release_ctlr; } - /* Now hpc_functions (slot->hpc_ops->functions) are ready */ - t_slot = shpchp_find_slot(ctrl, first_device_num); - - /* Check for operation bus speed */ - rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed); - dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot); - - if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) { - err(SHPC_MODULE_NAME ": Can't get current bus speed. " - "Set to 33MHz PCI.\n"); - ctrl->speed = PCI_SPEED_33MHz; - } - rc = shpchp_create_ctrl_files(ctrl); if (rc) goto err_cleanup_slots; diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 158ac783609..6bb84734cd6 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -57,9 +57,8 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) return 0; } -u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) +u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u32 event_type; @@ -81,9 +80,8 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) } -u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) +u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 getstatus; u32 event_type; @@ -120,9 +118,8 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) return 1; } -u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) +u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u32 event_type; @@ -154,9 +151,8 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) return 1; } -u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) +u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u32 event_type; @@ -497,10 +493,12 @@ static void handle_button_press_event(struct slot *p_slot) p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (getstatus) { p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->name); + info("PCI slot #%s - powering off due to button " + "press.\n", p_slot->name); } else { p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->name); + info("PCI slot #%s - powering on due to button " + "press.\n", p_slot->name); } /* blink green LED and turn off amber */ p_slot->hpc_ops->green_led_blink(p_slot); @@ -523,7 +521,8 @@ static void handle_button_press_event(struct slot *p_slot) else p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->set_attention_status(p_slot, 0); - info(msg_button_cancel, p_slot->name); + info("PCI slot #%s - action canceled due to button press\n", + p_slot->name); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 83a5226ba9e..b7bede4b7c2 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -212,44 +212,40 @@ #define SLOT_SERR_INT_MASK 0x3 DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ -static int ctlr_seq_num = 0; /* Controller sequenc # */ -static spinlock_t list_lock; - static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); static irqreturn_t shpc_isr(int irq, void *dev_id); -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec); +static void start_int_poll_timer(struct controller *ctrl, int sec); static int hpc_check_cmd_status(struct controller *ctrl); static inline u8 shpc_readb(struct controller *ctrl, int reg) { - return readb(ctrl->hpc_ctlr_handle->creg + reg); + return readb(ctrl->creg + reg); } static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) { - writeb(val, ctrl->hpc_ctlr_handle->creg + reg); + writeb(val, ctrl->creg + reg); } static inline u16 shpc_readw(struct controller *ctrl, int reg) { - return readw(ctrl->hpc_ctlr_handle->creg + reg); + return readw(ctrl->creg + reg); } static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) { - writew(val, ctrl->hpc_ctlr_handle->creg + reg); + writew(val, ctrl->creg + reg); } static inline u32 shpc_readl(struct controller *ctrl, int reg) { - return readl(ctrl->hpc_ctlr_handle->creg + reg); + return readl(ctrl->creg + reg); } static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) { - writel(val, ctrl->hpc_ctlr_handle->creg + reg); + writel(val, ctrl->creg + reg); } static inline int shpc_indirect_read(struct controller *ctrl, int index, @@ -268,21 +264,20 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index, /* * This is the interrupt polling timeout function. */ -static void int_poll_timeout(unsigned long lphp_ctlr) +static void int_poll_timeout(unsigned long data) { - struct php_ctlr_state_s *php_ctlr = - (struct php_ctlr_state_s *)lphp_ctlr; + struct controller *ctrl = (struct controller *)data; DBG_ENTER_ROUTINE /* Poll for interrupt events. regs == NULL => polling */ - shpc_isr(0, php_ctlr->callback_instance_id); + shpc_isr(0, ctrl); - init_timer(&php_ctlr->int_poll_timer); + init_timer(&ctrl->poll_timer); if (!shpchp_poll_time) shpchp_poll_time = 2; /* default polling interval is 2 sec */ - start_int_poll_timer(php_ctlr, shpchp_poll_time); + start_int_poll_timer(ctrl, shpchp_poll_time); DBG_LEAVE_ROUTINE } @@ -290,16 +285,16 @@ static void int_poll_timeout(unsigned long lphp_ctlr) /* * This function starts the interrupt polling timer. */ -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) +static void start_int_poll_timer(struct controller *ctrl, int sec) { /* Clamp to sane value */ if ((sec <= 0) || (sec > 60)) sec = 2; - php_ctlr->int_poll_timer.function = &int_poll_timeout; - php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; - php_ctlr->int_poll_timer.expires = jiffies + sec * HZ; - add_timer(&php_ctlr->int_poll_timer); + ctrl->poll_timer.function = &int_poll_timeout; + ctrl->poll_timer.data = (unsigned long)ctrl; + ctrl->poll_timer.expires = jiffies + sec * HZ; + add_timer(&ctrl->poll_timer); } static inline int is_ctrl_busy(struct controller *ctrl) @@ -666,33 +661,8 @@ static void hpc_set_green_led_blink(struct slot *slot) shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK); } -int shpc_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, /* number of slots in this HPC */ - int *first_device_num, /* PCI dev num of the first slot in this SHPC */ - int *physical_slot_num, /* phy slot num of the first slot in this SHPC */ - int *updown, /* physical_slot_num increament: 1 or -1 */ - int *flags) -{ - u32 slot_config; - - DBG_ENTER_ROUTINE - - slot_config = shpc_readl(ctrl, SLOT_CONFIG); - *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; - *num_ctlr_slots = slot_config & SLOT_NUM; - *physical_slot_num = (slot_config & PSN) >> 16; - *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1; - - dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); - - DBG_LEAVE_ROUTINE - return 0; -} - static void hpc_release_ctlr(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - struct php_ctlr_state_s *p, *p_prev; int i; u32 slot_reg, serr_int; @@ -722,40 +692,15 @@ static void hpc_release_ctlr(struct controller *ctrl) serr_int &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); - if (shpchp_poll_mode) { - del_timer(&php_ctlr->int_poll_timer); - } else { - if (php_ctlr->irq) { - free_irq(php_ctlr->irq, ctrl); - php_ctlr->irq = 0; - pci_disable_msi(php_ctlr->pci_dev); - } - } - - if (php_ctlr->pci_dev) { - iounmap(php_ctlr->creg); - release_mem_region(ctrl->mmio_base, ctrl->mmio_size); - php_ctlr->pci_dev = NULL; - } - - spin_lock(&list_lock); - p = php_ctlr_list_head; - p_prev = NULL; - while (p) { - if (p == php_ctlr) { - if (p_prev) - p_prev->pnext = p->pnext; - else - php_ctlr_list_head = p->pnext; - break; - } else { - p_prev = p; - p = p->pnext; - } + if (shpchp_poll_mode) + del_timer(&ctrl->poll_timer); + else { + free_irq(ctrl->pci_dev->irq, ctrl); + pci_disable_msi(ctrl->pci_dev); } - spin_unlock(&list_lock); - kfree(php_ctlr); + iounmap(ctrl->creg); + release_mem_region(ctrl->mmio_base, ctrl->mmio_size); /* * If this is the last controller to be released, destroy the @@ -764,8 +709,7 @@ static void hpc_release_ctlr(struct controller *ctrl) if (atomic_dec_and_test(&shpchp_num_controllers)) destroy_workqueue(shpchp_wq); -DBG_LEAVE_ROUTINE - + DBG_LEAVE_ROUTINE } static int hpc_power_on_slot(struct slot * slot) @@ -891,7 +835,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) static irqreturn_t shpc_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u32 serr_int, slot_reg, intr_loc, intr_loc2; int hp_slot; @@ -942,20 +885,16 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) __FUNCTION__, hp_slot, slot_reg); if (slot_reg & MRL_CHANGE_DETECTED) - php_ctlr->switch_change_callback( - hp_slot, php_ctlr->callback_instance_id); + shpchp_handle_switch_change(hp_slot, ctrl); if (slot_reg & BUTTON_PRESS_DETECTED) - php_ctlr->attention_button_callback( - hp_slot, php_ctlr->callback_instance_id); + shpchp_handle_attention_button(hp_slot, ctrl); if (slot_reg & PRSNT_CHANGE_DETECTED) - php_ctlr->presence_change_callback( - hp_slot , php_ctlr->callback_instance_id); + shpchp_handle_presence_change(hp_slot, ctrl); if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) - php_ctlr->power_fault_callback( - hp_slot, php_ctlr->callback_instance_id); + shpchp_handle_power_fault(hp_slot, ctrl); /* Clear all slot events */ slot_reg &= ~SLOT_REG_RSVDZ_MASK; @@ -1114,10 +1053,8 @@ static struct hpc_ops shpchp_hpc_ops = { .release_ctlr = hpc_release_ctlr, }; -int shpc_init(struct controller * ctrl, struct pci_dev * pdev) +int shpc_init(struct controller *ctrl, struct pci_dev *pdev) { - struct php_ctlr_state_s *php_ctlr, *p; - void *instance_id = ctrl; int rc = -1, num_slots = 0; u8 hp_slot; u32 shpc_base_offset; @@ -1128,16 +1065,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ - spin_lock_init(&list_lock); - php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL); - - if (!php_ctlr) { /* allocate controller state data */ - err("%s: HPC controller memory allocation error!\n", __FUNCTION__); - goto abort; - } - - php_ctlr->pci_dev = pdev; /* save pci_dev in context */ - if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450)) { /* amd shpc driver doesn't use Base Offset; assume 0 */ @@ -1147,20 +1074,20 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC); if (!ctrl->cap_offset) { err("%s : cap_offset == 0\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); if (rc) { err("%s: cannot read base_offset\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } rc = shpc_indirect_read(ctrl, 3, &tempdword); if (rc) { err("%s: cannot read slot config\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } num_slots = tempdword & SLOT_NUM; dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); @@ -1170,7 +1097,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) if (rc) { err("%s: cannot read creg (index = %d)\n", __FUNCTION__, i); - goto abort_free_ctlr; + goto abort; } dbg("%s: offset %d: value %x\n", __FUNCTION__,i, tempdword); @@ -1187,24 +1114,24 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) rc = pci_enable_device(pdev); if (rc) { err("%s: pci_enable_device failed\n", __FUNCTION__); - goto abort_free_ctlr; + goto abort; } if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { err("%s: cannot reserve MMIO region\n", __FUNCTION__); rc = -1; - goto abort_free_ctlr; + goto abort; } - php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); - if (!php_ctlr->creg) { + ctrl->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); + if (!ctrl->creg) { err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, ctrl->mmio_size, ctrl->mmio_base); release_mem_region(ctrl->mmio_base, ctrl->mmio_size); rc = -1; - goto abort_free_ctlr; + goto abort; } - dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); + dbg("%s: ctrl->creg %p\n", __FUNCTION__, ctrl->creg); mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->cmd_lock); @@ -1212,23 +1139,14 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) /* Setup wait queue */ init_waitqueue_head(&ctrl->queue); - /* Find the IRQ */ - php_ctlr->irq = pdev->irq; - php_ctlr->attention_button_callback = shpchp_handle_attention_button, - php_ctlr->switch_change_callback = shpchp_handle_switch_change; - php_ctlr->presence_change_callback = shpchp_handle_presence_change; - php_ctlr->power_fault_callback = shpchp_handle_power_fault; - php_ctlr->callback_instance_id = instance_id; - - ctrl->hpc_ctlr_handle = php_ctlr; ctrl->hpc_ops = &shpchp_hpc_ops; /* Return PCI Controller Info */ slot_config = shpc_readl(ctrl, SLOT_CONFIG); - php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; - php_ctlr->num_slots = slot_config & SLOT_NUM; - dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); - dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); + ctrl->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; + ctrl->num_slots = slot_config & SLOT_NUM; + ctrl->first_slot = (slot_config & PSN) >> 16; + ctrl->slot_num_inc = ((slot_config & UPDOWN) >> 29) ? 1 : -1; /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); @@ -1243,7 +1161,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) /* Mask the MRL sensor SERR Mask of individual slot in * Slot SERR-INT Mask & clear all the existing event if any */ - for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); @@ -1255,24 +1173,27 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } - if (shpchp_poll_mode) {/* Install interrupt polling code */ - /* Install and start the interrupt polling timer */ - init_timer(&php_ctlr->int_poll_timer); - start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ + if (shpchp_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 = pci_enable_msi(pdev); if (rc) { info("Can't get msi for the hotplug controller\n"); info("Use INTx for the hotplug controller\n"); - } else - php_ctlr->irq = pdev->irq; + } - rc = request_irq(php_ctlr->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *) ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); + rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, + MY_NAME, (void *)ctrl); + dbg("%s: request_irq %d for hpc%d (returns %d)\n", + __FUNCTION__, ctrl->pci_dev->irq, + atomic_read(&shpchp_num_controllers), rc); if (rc) { - err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); - goto abort_free_ctlr; + err("Can't get irq %d for the hotplug controller\n", + ctrl->pci_dev->irq); + goto abort_iounmap; } } dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__, @@ -1280,24 +1201,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) PCI_FUNC(pdev->devfn), pdev->irq); get_hp_hw_control_from_firmware(pdev); - /* Add this HPC instance into the HPC list */ - spin_lock(&list_lock); - if (php_ctlr_list_head == 0) { - php_ctlr_list_head = php_ctlr; - p = php_ctlr_list_head; - p->pnext = NULL; - } else { - p = php_ctlr_list_head; - - while (p->pnext) - p = p->pnext; - - p->pnext = php_ctlr; - } - spin_unlock(&list_lock); - - ctlr_seq_num++; - /* * If this is the first controller to be initialized, * initialize the shpchpd work queue @@ -1306,14 +1209,14 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) shpchp_wq = create_singlethread_workqueue("shpchpd"); if (!shpchp_wq) { rc = -ENOMEM; - goto abort_free_ctlr; + goto abort_iounmap; } } /* * Unmask all event interrupts of all slots */ - for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, hp_slot, slot_reg); @@ -1336,10 +1239,8 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) return 0; /* We end up here for the many possible ways to fail this API. */ -abort_free_ctlr: - if (php_ctlr->creg) - iounmap(php_ctlr->creg); - kfree(php_ctlr); +abort_iounmap: + iounmap(ctrl->creg); abort: DBG_LEAVE_ROUTINE return rc; diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 0a8d1cce9fa..279c940a003 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -99,14 +99,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) int pos; int irq; - pos = pci_find_capability(dev, PCI_CAP_ID_HT); - while (pos) { - u8 subtype; - pci_read_config_byte(dev, pos + 3, &subtype); - if (subtype == HT_CAPTYPE_IRQ) - break; - pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT); - } + pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); if (!pos) return -EINVAL; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e5ae3a0c13b..92d5e8db0de 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -150,8 +150,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, } /** - * pci_match_device - Tell if a PCI device structure has a matching - * PCI device id structure + * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure * @drv: the PCI driver to match against * @dev: the PCI device structure to match against * @@ -162,14 +161,9 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev) { - const struct pci_device_id *id; struct pci_dynid *dynid; - id = pci_match_id(drv->id_table, dev); - if (id) - return id; - - /* static ids didn't match, lets look at the dynamic ones */ + /* Look at the dynamic ids first, before the static ones */ spin_lock(&drv->dynids.lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (pci_match_one_device(&dynid->id, dev)) { @@ -178,7 +172,8 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv, } } spin_unlock(&drv->dynids.lock); - return NULL; + + return pci_match_id(drv->id_table, dev); } static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, @@ -357,6 +352,8 @@ static int pci_device_resume_early(struct device * dev) struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; + pci_fixup_device(pci_fixup_resume, pci_dev); + if (drv && drv->resume_early) error = drv->resume_early(pci_dev); return error; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5a14b73cf3a..206c834d263 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -68,12 +68,14 @@ pci_max_busnr(void) #endif /* 0 */ -static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) +#define PCI_FIND_CAP_TTL 48 + +static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap, int *ttl) { u8 id; - int ttl = 48; - while (ttl--) { + while ((*ttl)--) { pci_bus_read_config_byte(bus, devfn, pos, &pos); if (pos < 0x40) break; @@ -89,6 +91,14 @@ static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, return 0; } +static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, + u8 pos, int cap) +{ + int ttl = PCI_FIND_CAP_TTL; + + return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); +} + int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) { return __pci_find_next_cap(dev->bus, dev->devfn, @@ -96,10 +106,10 @@ int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) } EXPORT_SYMBOL_GPL(pci_find_next_capability); -static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap) +static int __pci_bus_find_cap_start(struct pci_bus *bus, + unsigned int devfn, u8 hdr_type) { u16 status; - u8 pos; pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status); if (!(status & PCI_STATUS_CAP_LIST)) @@ -108,15 +118,14 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty switch (hdr_type) { case PCI_HEADER_TYPE_NORMAL: case PCI_HEADER_TYPE_BRIDGE: - pos = PCI_CAPABILITY_LIST; - break; + return PCI_CAPABILITY_LIST; case PCI_HEADER_TYPE_CARDBUS: - pos = PCI_CB_CAPABILITY_LIST; - break; + return PCI_CB_CAPABILITY_LIST; default: return 0; } - return __pci_find_next_cap(bus, devfn, pos, cap); + + return 0; } /** @@ -140,7 +149,13 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty */ int pci_find_capability(struct pci_dev *dev, int cap) { - return __pci_bus_find_cap(dev->bus, dev->devfn, dev->hdr_type, cap); + int pos; + + pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); + if (pos) + pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap); + + return pos; } /** @@ -158,11 +173,16 @@ int pci_find_capability(struct pci_dev *dev, int cap) */ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) { + int pos; u8 hdr_type; pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type); - return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap); + pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f); + if (pos) + pos = __pci_find_next_cap(bus, devfn, pos, cap); + + return pos; } /** @@ -214,6 +234,75 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) } EXPORT_SYMBOL_GPL(pci_find_ext_capability); +static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) +{ + int rc, ttl = PCI_FIND_CAP_TTL; + u8 cap, mask; + + if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST) + mask = HT_3BIT_CAP_MASK; + else + mask = HT_5BIT_CAP_MASK; + + pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos, + PCI_CAP_ID_HT, &ttl); + while (pos) { + rc = pci_read_config_byte(dev, pos + 3, &cap); + if (rc != PCIBIOS_SUCCESSFUL) + return 0; + + if ((cap & mask) == ht_cap) + return pos; + + pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, + pos + PCI_CAP_LIST_NEXT, + PCI_CAP_ID_HT, &ttl); + } + + return 0; +} +/** + * pci_find_next_ht_capability - query a device's Hypertransport capabilities + * @dev: PCI device to query + * @pos: Position from which to continue searching + * @ht_cap: Hypertransport capability code + * + * To be used in conjunction with pci_find_ht_capability() to search for + * all capabilities matching @ht_cap. @pos should always be a value returned + * from pci_find_ht_capability(). + * + * NB. To be 100% safe against broken PCI devices, the caller should take + * steps to avoid an infinite loop. + */ +int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap) +{ + return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap); +} +EXPORT_SYMBOL_GPL(pci_find_next_ht_capability); + +/** + * pci_find_ht_capability - query a device's Hypertransport capabilities + * @dev: PCI device to query + * @ht_cap: Hypertransport capability code + * + * Tell if a device supports a given Hypertransport capability. + * Returns an address within the device's PCI configuration space + * or 0 in case the device does not support the request capability. + * The address points to the PCI capability, of type PCI_CAP_ID_HT, + * which has a Hypertransport capability matching @ht_cap. + */ +int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) +{ + int pos; + + pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); + if (pos) + pos = __pci_find_next_ht_cap(dev, pos, ht_cap); + + return pos; +} +EXPORT_SYMBOL_GPL(pci_find_ht_capability); + /** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index b4da7954611..f17e7ed2b2a 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -90,7 +90,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, return -ENODEV; pci_set_master(dev); - if (!dev->irq) { + if (!dev->irq && dev->pin) { printk(KERN_WARNING "%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n", __FUNCTION__, dev->device, dev->vendor); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6a3c1e72890..0e0401dd02c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -639,6 +639,8 @@ static void pci_read_irq(struct pci_dev *dev) dev->irq = irq; } +#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) + /** * pci_setup_device - fill in class and map information of a device * @dev: the device structure to fill @@ -692,18 +694,18 @@ static int pci_setup_device(struct pci_dev * dev) if ((progif & 1) == 0) { dev->resource[0].start = 0x1F0; dev->resource[0].end = 0x1F7; - dev->resource[0].flags = IORESOURCE_IO; + dev->resource[0].flags = LEGACY_IO_RESOURCE; dev->resource[1].start = 0x3F6; dev->resource[1].end = 0x3F6; - dev->resource[1].flags = IORESOURCE_IO; + dev->resource[1].flags = LEGACY_IO_RESOURCE; } if ((progif & 4) == 0) { dev->resource[2].start = 0x170; dev->resource[2].end = 0x177; - dev->resource[2].flags = IORESOURCE_IO; + dev->resource[2].flags = LEGACY_IO_RESOURCE; dev->resource[3].start = 0x376; dev->resource[3].end = 0x376; - dev->resource[3].flags = IORESOURCE_IO; + dev->resource[3].flags = LEGACY_IO_RESOURCE; } } break; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 9ca9b9bf616..c913ea4e545 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -36,7 +36,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRID /* Deal with broken BIOS'es that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ -static void __devinit quirk_passive_release(struct pci_dev *dev) +static void quirk_passive_release(struct pci_dev *dev) { struct pci_dev *d = NULL; unsigned char dlc; @@ -53,6 +53,7 @@ static void __devinit quirk_passive_release(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release ); /* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround but VIA don't answer queries. If you happen to have good contacts at VIA @@ -134,7 +135,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir * Updated based on further information from the site and also on * information provided by VIA */ -static void __devinit quirk_vialatency(struct pci_dev *dev) +static void quirk_vialatency(struct pci_dev *dev) { struct pci_dev *p; u8 rev; @@ -185,6 +186,10 @@ exit: DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); +/* Must restore this on a resume from RAM */ +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency ); /* * VIA Apollo VP3 needs ETBF on BT848/878 @@ -532,7 +537,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235 * TODO: When we have device-specific interrupt routers, * this code will go away from quirks. */ -static void __devinit quirk_via_ioapic(struct pci_dev *dev) +static void quirk_via_ioapic(struct pci_dev *dev) { u8 tmp; @@ -548,6 +553,7 @@ static void __devinit quirk_via_ioapic(struct pci_dev *dev) pci_write_config_byte (dev, 0x58, tmp); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic ); /* * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit. @@ -555,7 +561,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_i * Set this bit to get rid of cycle wastage. * Otherwise uncritical. */ -static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev) +static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev) { u8 misc_control2; #define BYPASS_APIC_DEASSERT 8 @@ -567,6 +573,7 @@ static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert); /* * The AMD io apic can hang the box when an apic irq is masked. @@ -600,7 +607,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw ); #define AMD8131_revB0 0x11 #define AMD8131_MISC 0x40 #define AMD8131_NIOAMODE_BIT 0 -static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) +static void quirk_amd_8131_ioapic(struct pci_dev *dev) { unsigned char revid, tmp; @@ -616,6 +623,7 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); #endif /* CONFIG_X86_IO_APIC */ @@ -641,48 +649,67 @@ static void __devinit quirk_via_acpi(struct pci_dev *d) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); + /* - * Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip - * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature: - * when written, it makes an internal connection to the PIC. - * For these devices, this register is defined to be 4 bits wide. - * Normally this is fine. However for IO-APIC motherboards, or - * non-x86 architectures (yes Via exists on PPC among other places), - * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get - * interrupts delivered properly. - * - * Some of the on-chip devices are actually '586 devices' so they are - * listed here. + * VIA bridges which have VLink */ -static int via_irq_fixup_needed = -1; +static int via_vlink_dev_lo = -1, via_vlink_dev_hi = 18; -/* - * As some VIA hardware is available in PCI-card form, we need to restrict - * this quirk to VIA PCI hardware built onto VIA-based motherboards only. - * We try to locate a VIA southbridge before deciding whether the quirk - * should be applied. +static void quirk_via_bridge(struct pci_dev *dev) +{ + /* See what bridge we have and find the device ranges */ + switch (dev->device) { + case PCI_DEVICE_ID_VIA_82C686: + /* The VT82C686 is special, it attaches to PCI and can have + any device number. All its subdevices are functions of + that single device. */ + via_vlink_dev_lo = PCI_SLOT(dev->devfn); + via_vlink_dev_hi = PCI_SLOT(dev->devfn); + break; + case PCI_DEVICE_ID_VIA_8237: + case PCI_DEVICE_ID_VIA_8237A: + via_vlink_dev_lo = 15; + break; + case PCI_DEVICE_ID_VIA_8235: + via_vlink_dev_lo = 16; + break; + case PCI_DEVICE_ID_VIA_8231: + case PCI_DEVICE_ID_VIA_8233_0: + case PCI_DEVICE_ID_VIA_8233A: + case PCI_DEVICE_ID_VIA_8233C_0: + via_vlink_dev_lo = 17; + break; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233C_0, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A, quirk_via_bridge); + +/** + * quirk_via_vlink - VIA VLink IRQ number update + * @dev: PCI device + * + * If the device we are dealing with is on a PIC IRQ we need to + * ensure that the IRQ line register which usually is not relevant + * for PCI cards, is actually written so that interrupts get sent + * to the right place. + * We only do this on systems where a VIA south bridge was detected, + * and only for VIA devices on the motherboard (see quirk_via_bridge + * above). */ -static const struct pci_device_id via_irq_fixup_tbl[] = { - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = PCI_CLASS_BRIDGE_ISA << 8, - .class_mask = 0xffff00, - }, - { 0, }, -}; - -static void quirk_via_irq(struct pci_dev *dev) + +static void quirk_via_vlink(struct pci_dev *dev) { u8 irq, new_irq; - if (via_irq_fixup_needed == -1) - via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl); - - if (!via_irq_fixup_needed) + /* Check if we have VLink at all */ + if (via_vlink_dev_lo == -1) return; new_irq = dev->irq; @@ -691,15 +718,23 @@ static void quirk_via_irq(struct pci_dev *dev) if (!new_irq || new_irq > 15) return; + /* Internal device ? */ + if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) > via_vlink_dev_hi || + PCI_SLOT(dev->devfn) < via_vlink_dev_lo) + return; + + /* This is an internal VLink device on a PIC interrupt. The BIOS + ought to have set this but may not have, so we redo it */ + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); if (new_irq != irq) { - printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n", + printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n", pci_name(dev), irq, new_irq); udelay(15); /* unknown if delay really needed */ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_vlink); /* * VIA VT82C598 has its device ID settable and many BIOSes @@ -720,13 +755,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt * do this even if the Linux CardBus driver is not loaded, because * the Linux i82365 driver does not (and should not) handle CardBus. */ -static void __devinit quirk_cardbus_legacy(struct pci_dev *dev) +static void quirk_cardbus_legacy(struct pci_dev *dev) { if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class) return; pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0); } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy); +DECLARE_PCI_FIXUP_RESUME(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy); /* * Following the PCI ordering rules is optional on the AMD762. I'm not @@ -735,7 +771,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy); * To be fair to AMD, it follows the spec by default, its BIOS people * who turn it off! */ -static void __devinit quirk_amd_ordering(struct pci_dev *dev) +static void quirk_amd_ordering(struct pci_dev *dev) { u32 pcic; pci_read_config_dword(dev, 0x4C, &pcic); @@ -749,6 +785,7 @@ static void __devinit quirk_amd_ordering(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering ); /* * DreamWorks provided workaround for Dunord I-3000 problem @@ -784,7 +821,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge * datasheets found at http://www.national.com/ds/GX for info on what * these bits do. <christer@weinigel.se> */ -static void __init quirk_mediagx_master(struct pci_dev *dev) +static void quirk_mediagx_master(struct pci_dev *dev) { u8 reg; pci_read_config_byte(dev, 0x41, ®); @@ -795,13 +832,14 @@ static void __init quirk_mediagx_master(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master ); /* * Ensure C0 rev restreaming is off. This is normally done by * the BIOS but in the odd case it is not the results are corruption * hence the presence of a Linux check */ -static void __init quirk_disable_pxb(struct pci_dev *pdev) +static void quirk_disable_pxb(struct pci_dev *pdev) { u16 config; u8 rev; @@ -817,7 +855,25 @@ static void __init quirk_disable_pxb(struct pci_dev *pdev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); + + +static void __devinit quirk_sb600_sata(struct pci_dev *pdev) +{ + /* set sb600 sata to ahci mode */ + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u8 tmp; + + pci_read_config_byte(pdev, 0x40, &tmp); + pci_write_config_byte(pdev, 0x40, tmp|1); + pci_write_config_byte(pdev, 0x9, 1); + pci_write_config_byte(pdev, 0xa, 6); + pci_write_config_byte(pdev, 0x40, tmp); + pdev->class = 0x010601; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata); /* * Serverworks CSB5 IDE does not fully support native mode @@ -874,7 +930,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e * runs everywhere at present we suppress the printk output in most * irrelevant cases. */ -static void __init k8t_sound_hostbridge(struct pci_dev *dev) +static void k8t_sound_hostbridge(struct pci_dev *dev) { unsigned char val; @@ -893,8 +949,8 @@ static void __init k8t_sound_hostbridge(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); -#ifndef CONFIG_ACPI_SLEEP /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge * is not activated. The myth is that Asus said that they do not want the @@ -906,12 +962,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it * becomes necessary to do this tweak in two steps -- I've chosen the Host * bridge as trigger. - * - * Actually, leaving it unhidden and not redoing the quirk over suspend2ram - * will cause thermal management to break down, and causing machine to - * overheat. */ -static int __initdata asus_hides_smbus; +static int asus_hides_smbus; static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) { @@ -958,6 +1010,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x186a: /* M6Ne notebook */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + switch (dev->subsystem_device) { + case 0x80f2: /* P4P800-X */ + asus_hides_smbus = 1; + } if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { switch (dev->subsystem_device) { case 0x1882: /* M6V notebook */ @@ -1019,7 +1076,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, as DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); -static void __init asus_hides_smbus_lpc(struct pci_dev *dev) +static void asus_hides_smbus_lpc(struct pci_dev *dev) { u16 val; @@ -1042,8 +1099,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asu DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); -static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) +static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev) { u32 val, rcba; void __iomem *base; @@ -1059,19 +1122,19 @@ static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n"); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); - -#endif +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); /* * SiS 96x south bridge: BIOS typically hides SMBus device... */ -static void __init quirk_sis_96x_smbus(struct pci_dev *dev) +static void quirk_sis_96x_smbus(struct pci_dev *dev) { u8 val = 0; - printk(KERN_INFO "Enabling SiS 96x SMBus.\n"); - pci_read_config_byte(dev, 0x77, &val); - pci_write_config_byte(dev, 0x77, val & ~0x10); pci_read_config_byte(dev, 0x77, &val); + if (val & 0x10) { + printk(KERN_INFO "Enabling SiS 96x SMBus.\n"); + pci_write_config_byte(dev, 0x77, val & ~0x10); + } } /* @@ -1086,7 +1149,7 @@ static int __devinitdata sis_96x_compatible = 0; #define SIS_DETECT_REGISTER 0x40 -static void __init quirk_sis_503(struct pci_dev *dev) +static void quirk_sis_503(struct pci_dev *dev) { u8 reg; u16 devid; @@ -1103,11 +1166,12 @@ static void __init quirk_sis_503(struct pci_dev *dev) printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible); /* - * Ok, it now shows up as a 96x.. The 96x quirks are after - * the 503 quirk in the quirk table, so they'll automatically - * run and enable things like the SMBus device + * Ok, it now shows up as a 96x.. run the 96x quirk by + * hand in case it has already been processed. + * (depends on link order, which is apparently not guaranteed) */ dev->device = devid; + quirk_sis_96x_smbus(dev); } static void __init quirk_sis_96x_compatible(struct pci_dev *dev) @@ -1122,13 +1186,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); /* * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller * and MC97 modem controller are disabled when a second PCI soundcard is * present. This patch, tweaking the VT8237 ISA bridge, enables them. * -- bjd */ -static void __init asus_hides_ac97_lpc(struct pci_dev *dev) +static void asus_hides_ac97_lpc(struct pci_dev *dev) { u8 val; int asus_hides_ac97 = 0; @@ -1159,6 +1224,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); + + +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); + #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) /* @@ -1167,7 +1240,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_ * the PCI scanning. */ -static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev) +static void quirk_jmicron_dualfn(struct pci_dev *pdev) { u32 conf; u8 hdr; @@ -1189,8 +1262,8 @@ static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev) pci_read_config_dword(pdev, 0x40, &conf); /* Enable dual function mode, AHCI on fn 0, IDE fn1 */ /* Set the class codes correctly and then direct IDE 0 */ - conf &= ~0x000F0200; /* Clear bit 9 and 16-19 */ - conf |= 0x00C20002; /* Set bit 1, 17, 22, 23 */ + conf &= ~0x000FF200; /* Clear bit 9 and 12-19 */ + conf |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */ pci_write_config_dword(pdev, 0x40, conf); /* Reconfigure so that the PCI scanner discovers the @@ -1205,6 +1278,7 @@ static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); #endif @@ -1532,6 +1606,8 @@ extern struct pci_fixup __start_pci_fixups_final[]; extern struct pci_fixup __end_pci_fixups_final[]; extern struct pci_fixup __start_pci_fixups_enable[]; extern struct pci_fixup __end_pci_fixups_enable[]; +extern struct pci_fixup __start_pci_fixups_resume[]; +extern struct pci_fixup __end_pci_fixups_resume[]; void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) @@ -1559,6 +1635,11 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) end = __end_pci_fixups_enable; break; + case pci_fixup_resume: + start = __start_pci_fixups_resume; + end = __end_pci_fixups_resume; + break; + default: /* stupid compiler warning, you would think with an enum... */ return; @@ -1596,7 +1677,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); * Force it to be linked by setting the corresponding control bit in the * config space. */ -static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) +static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) { uint8_t b; if (pci_read_config_byte(dev, 0xf41, &b) == 0) { @@ -1610,6 +1691,8 @@ static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_pcie_aer_ext_cap); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, + quirk_nvidia_ck804_pcie_aer_ext_cap); #ifdef CONFIG_PCI_MSI /* To disable MSI globally */ @@ -1644,19 +1727,23 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_ * return 1 if a HT MSI capability is found and enabled */ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) { - u8 pos; - int ttl; - for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48; - pos && ttl; - pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) { - u32 cap_hdr; - /* MSI mapping section according to Hypertransport spec */ - if (pci_read_config_dword(dev, pos, &cap_hdr) == 0 - && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) { - printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n", - pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled"); - return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */ + int pos, ttl = 48; + + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) + { + printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n", + flags & HT_MSI_FLAGS_ENABLE ? + "enabled" : "disabled", pci_name(dev)); + return (flags & HT_MSI_FLAGS_ENABLE) != 0; } + + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); } return 0; } @@ -1688,8 +1775,9 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) * a single one having MSI is enough to be sure that MSI are supported. */ pdev = pci_get_slot(dev->bus, 0); - if (dev->subordinate && !msi_ht_cap_enabled(dev) - && !msi_ht_cap_enabled(pdev)) { + if (!pdev) + return; + if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { printk(KERN_WARNING "PCI: MSI quirk detected. " "MSI disabled on chipset %s.\n", pci_name(dev)); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 2f13eba5d5a..b2653c4afe9 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -193,6 +193,15 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, struct pci_dev *dev; WARN_ON(in_interrupt()); + + /* + * pci_find_subsys() can be called on the ide_setup() path, super-early + * in boot. But the down_read() will enable local interrupts, which + * can cause some machines to crash. So here we detect and flag that + * situation and bail out early. + */ + if (unlikely(list_empty(&pci_devices))) + return NULL; down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; @@ -259,6 +268,15 @@ pci_get_subsys(unsigned int vendor, unsigned int device, struct pci_dev *dev; WARN_ON(in_interrupt()); + + /* + * pci_get_subsys() can potentially be called by drivers super-early + * in boot. But the down_read() will enable local interrupts, which + * can cause some machines to crash. So here we detect and flag that + * situation and bail out early. + */ + if (unlikely(list_empty(&pci_devices))) + return NULL; down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; @@ -413,6 +431,24 @@ exit: return dev; } +const struct pci_device_id *pci_find_present(const struct pci_device_id *ids) +{ + struct pci_dev *dev; + const struct pci_device_id *found = NULL; + + WARN_ON(in_interrupt()); + down_read(&pci_bus_sem); + while (ids->vendor || ids->subvendor || ids->class_mask) { + list_for_each_entry(dev, &pci_devices, global_list) { + if ((found = pci_match_one_device(ids, dev)) != NULL) + break; + } + ids++; + } + up_read(&pci_bus_sem); + return found; +} + /** * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not. * @ids: A pointer to a null terminated list of struct pci_device_id structures @@ -426,25 +462,11 @@ exit: */ int pci_dev_present(const struct pci_device_id *ids) { - struct pci_dev *dev; - int found = 0; - - WARN_ON(in_interrupt()); - down_read(&pci_bus_sem); - while (ids->vendor || ids->subvendor || ids->class_mask) { - list_for_each_entry(dev, &pci_devices, global_list) { - if (pci_match_one_device(ids, dev)) { - found = 1; - goto exit; - } - } - ids++; - } -exit: - up_read(&pci_bus_sem); - return found; + return pci_find_present(ids) == NULL ? 0 : 1; } + EXPORT_SYMBOL(pci_dev_present); +EXPORT_SYMBOL(pci_find_present); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 8f7bcf56f14..89f3036f0de 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -41,7 +41,7 @@ * have a P2P bridge below a cardbus bridge, we need 4K. */ #define CARDBUS_IO_SIZE (256) -#define CARDBUS_MEM_SIZE (32*1024*1024) +#define CARDBUS_MEM_SIZE (64*1024*1024) static void __devinit pbus_assign_resources_sorted(struct pci_bus *bus) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ab78e4bbdd8..cb4ced3560e 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -33,11 +33,22 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) u32 new, check, mask; int reg; - /* Ignore resources for unimplemented BARs and unused resource slots - for 64 bit BARs. */ + /* + * Ignore resources for unimplemented BARs and unused resource slots + * for 64 bit BARs. + */ if (!res->flags) return; + /* + * Ignore non-moveable resources. This might be legacy resources for + * which no functional BAR register exists or another important + * system resource we should better not move around in system address + * space. + */ + if (res->flags & IORESOURCE_PCI_FIXED) + return; + pcibios_resource_to_bus(dev, ®ion, res); pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for " @@ -212,6 +223,10 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) resource_size_t r_align; r = &dev->resource[i]; + + if (r->flags & IORESOURCE_PCI_FIXED) + continue; + r_align = r->end - r->start; if (!(r->flags) || r->parent) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 4f654c901c6..a724ab49a79 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -33,6 +33,8 @@ #include <asm/mach/time.h> +#include <asm/arch/at91_rtc.h> + #define AT91_RTC_FREQ 1 #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 1460f6b769f..e7851e3739a 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -1,5 +1,5 @@ /* - * An I2C driver for the Ricoh RS5C372 RTC + * An I2C driver for Ricoh RS5C372 and RV5C38[67] RTCs * * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> * Copyright (C) 2006 Tower Technologies @@ -13,7 +13,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> -#define DRV_VERSION "0.3" +#define DRV_VERSION "0.4" /* Addresses to scan */ static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; @@ -21,6 +21,13 @@ static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD; + +/* + * Ricoh has a family of I2C based RTCs, which differ only slightly from + * each other. Differences center on pinout (e.g. how many interrupts, + * output clock, etc) and how the control registers are used. The '372 + * is significant only because that's the one this driver first supported. + */ #define RS5C372_REG_SECS 0 #define RS5C372_REG_MINS 1 #define RS5C372_REG_HOURS 2 @@ -29,59 +36,142 @@ I2C_CLIENT_INSMOD; #define RS5C372_REG_MONTH 5 #define RS5C372_REG_YEAR 6 #define RS5C372_REG_TRIM 7 +# define RS5C372_TRIM_XSL 0x80 +# define RS5C372_TRIM_MASK 0x7F + +#define RS5C_REG_ALARM_A_MIN 8 /* or ALARM_W */ +#define RS5C_REG_ALARM_A_HOURS 9 +#define RS5C_REG_ALARM_A_WDAY 10 + +#define RS5C_REG_ALARM_B_MIN 11 /* or ALARM_D */ +#define RS5C_REG_ALARM_B_HOURS 12 +#define RS5C_REG_ALARM_B_WDAY 13 /* (ALARM_B only) */ + +#define RS5C_REG_CTRL1 14 +# define RS5C_CTRL1_AALE (1 << 7) /* or WALE */ +# define RS5C_CTRL1_BALE (1 << 6) /* or DALE */ +# define RV5C387_CTRL1_24 (1 << 5) +# define RS5C372A_CTRL1_SL1 (1 << 5) +# define RS5C_CTRL1_CT_MASK (7 << 0) +# define RS5C_CTRL1_CT0 (0 << 0) /* no periodic irq */ +# define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */ +#define RS5C_REG_CTRL2 15 +# define RS5C372_CTRL2_24 (1 << 5) +# define RS5C_CTRL2_XSTP (1 << 4) +# define RS5C_CTRL2_CTFG (1 << 2) +# define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */ +# define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */ + + +/* to read (style 1) or write registers starting at R */ +#define RS5C_ADDR(R) (((R) << 4) | 0) + + +enum rtc_type { + rtc_undef = 0, + rtc_rs5c372a, + rtc_rs5c372b, + rtc_rv5c386, + rtc_rv5c387a, +}; -#define RS5C372_TRIM_XSL 0x80 -#define RS5C372_TRIM_MASK 0x7F +/* 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); + * - we should use ALARM_A not ALARM_B (may be wrong on some boards) + */ +struct rs5c372 { + struct i2c_client *client; + struct rtc_device *rtc; + enum rtc_type type; + unsigned time24:1; + unsigned has_irq:1; + char buf[17]; + char *regs; + + /* on conversion to a "new style" i2c driver, this vanishes */ + struct i2c_client dev; +}; -#define RS5C372_REG_BASE 0 +static int rs5c_get_regs(struct rs5c372 *rs5c) +{ + struct i2c_client *client = rs5c->client; + struct i2c_msg msgs[] = { + { client->addr, I2C_M_RD, sizeof rs5c->buf, rs5c->buf }, + }; + + /* This implements the third reading method from the datasheet, using + * an internal address that's reset after each transaction (by STOP) + * to 0x0f ... so we read extra registers, and skip the first one. + * + * The first method doesn't work with the iop3xx adapter driver, on at + * 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); + return -EIO; + } -static int rs5c372_attach(struct i2c_adapter *adapter); -static int rs5c372_detach(struct i2c_client *client); -static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind); + dev_dbg(&client->dev, + "%02x %02x %02x (%02x) %02x %02x %02x (%02x), " + "%02x %02x %02x, %02x %02x %02x; %02x %02x\n", + rs5c->regs[0], rs5c->regs[1], rs5c->regs[2], rs5c->regs[3], + rs5c->regs[4], rs5c->regs[5], rs5c->regs[6], rs5c->regs[7], + rs5c->regs[8], rs5c->regs[9], rs5c->regs[10], rs5c->regs[11], + rs5c->regs[12], rs5c->regs[13], rs5c->regs[14], rs5c->regs[15]); -struct rs5c372 { - u8 reg_addr; - u8 regs[17]; - struct i2c_msg msg[1]; - struct i2c_client client; - struct rtc_device *rtc; -}; + return 0; +} -static struct i2c_driver rs5c372_driver = { - .driver = { - .name = "rs5c372", - }, - .attach_adapter = &rs5c372_attach, - .detach_client = &rs5c372_detach, -}; +static unsigned rs5c_reg2hr(struct rs5c372 *rs5c, unsigned reg) +{ + unsigned hour; -static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) + if (rs5c->time24) + return BCD2BIN(reg & 0x3f); + + hour = BCD2BIN(reg & 0x1f); + if (hour == 12) + hour = 0; + if (reg & 0x20) + hour += 12; + return hour; +} + +static unsigned rs5c_hr2reg(struct rs5c372 *rs5c, unsigned hour) { + if (rs5c->time24) + return BIN2BCD(hour); + + if (hour > 12) + return 0x20 | BIN2BCD(hour - 12); + if (hour == 12) + return 0x20 | BIN2BCD(12); + if (hour == 0) + return BIN2BCD(12); + return BIN2BCD(hour); +} - struct rs5c372 *rs5c372 = i2c_get_clientdata(client); - u8 *buf = &(rs5c372->regs[1]); +static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + struct rs5c372 *rs5c = i2c_get_clientdata(client); + int status = rs5c_get_regs(rs5c); - /* this implements the 3rd reading method, according - * to the datasheet. rs5c372 defaults to internal - * address 0xF, so 0x0 is in regs[1] - */ + if (status < 0) + return status; - if ((i2c_transfer(client->adapter, rs5c372->msg, 1)) != 1) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); - return -EIO; - } + tm->tm_sec = BCD2BIN(rs5c->regs[RS5C372_REG_SECS] & 0x7f); + tm->tm_min = BCD2BIN(rs5c->regs[RS5C372_REG_MINS] & 0x7f); + tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]); - tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f); - tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f); - tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f); - tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07); - tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f); + tm->tm_wday = BCD2BIN(rs5c->regs[RS5C372_REG_WDAY] & 0x07); + tm->tm_mday = BCD2BIN(rs5c->regs[RS5C372_REG_DAY] & 0x3f); /* tm->tm_mon is zero-based */ - tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1; + tm->tm_mon = BCD2BIN(rs5c->regs[RS5C372_REG_MONTH] & 0x1f) - 1; /* year is 1900 + tm->tm_year */ - tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100; + tm->tm_year = BCD2BIN(rs5c->regs[RS5C372_REG_YEAR]) + 100; dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", @@ -89,22 +179,25 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - return 0; + /* rtc might need initialization */ + return rtc_valid_tm(tm); } static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) { - unsigned char buf[8] = { RS5C372_REG_BASE }; + struct rs5c372 *rs5c = i2c_get_clientdata(client); + unsigned char buf[8]; - dev_dbg(&client->dev, - "%s: secs=%d, mins=%d, hours=%d " + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + buf[0] = RS5C_ADDR(RS5C372_REG_SECS); buf[1] = BIN2BCD(tm->tm_sec); buf[2] = BIN2BCD(tm->tm_min); - buf[3] = BIN2BCD(tm->tm_hour); + buf[3] = rs5c_hr2reg(rs5c, tm->tm_hour); buf[4] = BIN2BCD(tm->tm_wday); buf[5] = BIN2BCD(tm->tm_mday); buf[6] = BIN2BCD(tm->tm_mon + 1); @@ -118,21 +211,43 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) return 0; } +#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) +#define NEED_TRIM +#endif + +#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) +#define NEED_TRIM +#endif + +#ifdef NEED_TRIM static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) { struct rs5c372 *rs5c372 = i2c_get_clientdata(client); - u8 tmp = rs5c372->regs[RS5C372_REG_TRIM + 1]; + u8 tmp = rs5c372->regs[RS5C372_REG_TRIM]; if (osc) *osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; if (trim) { - *trim = tmp & RS5C372_TRIM_MASK; - dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim); + dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, tmp); + tmp &= RS5C372_TRIM_MASK; + if (tmp & 0x3e) { + int t = tmp & 0x3f; + + if (tmp & 0x40) + t = (~t | (s8)0xc0) + 1; + else + t = t - 1; + + tmp = t * 2; + } else + tmp = 0; + *trim = tmp; } return 0; } +#endif static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm) { @@ -144,25 +259,190 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) return rs5c372_set_datetime(to_i2c_client(dev), tm); } +#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) + +static int +rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); + unsigned char buf[2]; + int status; + + buf[1] = rs5c->regs[RS5C_REG_CTRL1]; + switch (cmd) { + case RTC_UIE_OFF: + case RTC_UIE_ON: + /* some 327a modes use a different IRQ pin for 1Hz irqs */ + if (rs5c->type == rtc_rs5c372a + && (buf[1] & RS5C372A_CTRL1_SL1)) + return -ENOIOCTLCMD; + case RTC_AIE_OFF: + case RTC_AIE_ON: + /* these irq management calls only make sense for chips + * which are wired up to an IRQ. + */ + if (!rs5c->has_irq) + return -ENOIOCTLCMD; + break; + default: + return -ENOIOCTLCMD; + } + + status = rs5c_get_regs(rs5c); + if (status < 0) + return status; + + buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); + switch (cmd) { + case RTC_AIE_OFF: /* alarm off */ + buf[1] &= ~RS5C_CTRL1_AALE; + break; + case RTC_AIE_ON: /* alarm on */ + buf[1] |= RS5C_CTRL1_AALE; + break; + case RTC_UIE_OFF: /* update off */ + buf[1] &= ~RS5C_CTRL1_CT_MASK; + break; + case RTC_UIE_ON: /* update on */ + buf[1] &= ~RS5C_CTRL1_CT_MASK; + buf[1] |= RS5C_CTRL1_CT4; + break; + } + if ((i2c_master_send(client, buf, 2)) != 2) { + printk(KERN_WARNING "%s: can't update alarm\n", + rs5c->rtc->name); + status = -EIO; + } else + rs5c->regs[RS5C_REG_CTRL1] = buf[1]; + return status; +} + +#else +#define rs5c_rtc_ioctl NULL +#endif + + +/* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI, + * which only exposes a polled programming interface; and since + * these calls map directly to those EFI requests; we don't demand + * we have an IRQ for this chip when we go through this API. + * + * The older x86_pc derived RTC_ALM_{READ,SET} calls require irqs + * though, managed through RTC_AIE_{ON,OFF} requests. + */ + +static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); + int status; + + status = rs5c_get_regs(rs5c); + if (status < 0) + return status; + + /* report alarm time */ + t->time.tm_sec = 0; + t->time.tm_min = BCD2BIN(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); + t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); + t->time.tm_mday = -1; + t->time.tm_mon = -1; + t->time.tm_year = -1; + t->time.tm_wday = -1; + t->time.tm_yday = -1; + t->time.tm_isdst = -1; + + /* ... and status */ + t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); + t->pending = !!(rs5c->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_AAFG); + + return 0; +} + +static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); + int status; + unsigned char buf[4]; + + /* only handle up to 24 hours in the future, like RTC_ALM_SET */ + if (t->time.tm_mday != -1 + || t->time.tm_mon != -1 + || t->time.tm_year != -1) + return -EINVAL; + + /* REVISIT: round up tm_sec */ + + /* if needed, disable irq (clears pending status) */ + status = rs5c_get_regs(rs5c); + if (status < 0) + return status; + if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) { + buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); + buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; + if (i2c_master_send(client, buf, 2) != 2) { + pr_debug("%s: can't disable alarm\n", rs5c->rtc->name); + return -EIO; + } + rs5c->regs[RS5C_REG_CTRL1] = buf[1]; + } + + /* set alarm */ + buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN); + buf[1] = BIN2BCD(t->time.tm_min); + buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour); + buf[3] = 0x7f; /* any/all days */ + if ((i2c_master_send(client, buf, 4)) != 4) { + pr_debug("%s: can't set alarm time\n", rs5c->rtc->name); + return -EIO; + } + + /* ... and maybe enable its irq */ + if (t->enabled) { + buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); + buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; + if ((i2c_master_send(client, buf, 2)) != 2) + printk(KERN_WARNING "%s: can't enable alarm\n", + rs5c->rtc->name); + rs5c->regs[RS5C_REG_CTRL1] = buf[1]; + } + + return 0; +} + +#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) + static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) { int err, osc, trim; err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim); if (err == 0) { - seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000); - seq_printf(seq, "trim\t: %d\n", trim); + seq_printf(seq, "crystal\t\t: %d.%03d KHz\n", + osc / 1000, osc % 1000); + seq_printf(seq, "trim\t\t: %d\n", trim); } return 0; } +#else +#define rs5c372_rtc_proc NULL +#endif + static const struct rtc_class_ops rs5c372_rtc_ops = { .proc = rs5c372_rtc_proc, + .ioctl = rs5c_rtc_ioctl, .read_time = rs5c372_rtc_read_time, .set_time = rs5c372_rtc_set_time, + .read_alarm = rs5c_read_alarm, + .set_alarm = rs5c_set_alarm, }; +#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) + static ssize_t rs5c372_sysfs_show_trim(struct device *dev, struct device_attribute *attr, char *buf) { @@ -172,7 +452,7 @@ static ssize_t rs5c372_sysfs_show_trim(struct device *dev, if (err) return err; - return sprintf(buf, "0x%2x\n", trim); + return sprintf(buf, "%d\n", trim); } static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); @@ -189,16 +469,35 @@ static ssize_t rs5c372_sysfs_show_osc(struct device *dev, } static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); -static int rs5c372_attach(struct i2c_adapter *adapter) +static int rs5c_sysfs_register(struct device *dev) { - return i2c_probe(adapter, &addr_data, rs5c372_probe); + int err; + + err = device_create_file(dev, &dev_attr_trim); + if (err) + return err; + err = device_create_file(dev, &dev_attr_osc); + if (err) + device_remove_file(dev, &dev_attr_trim); + + return err; +} + +#else +static int rs5c_sysfs_register(struct device *dev) +{ + return 0; } +#endif /* SYSFS */ + +static struct i2c_driver rs5c372_driver; static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) { int err = 0; struct i2c_client *client; struct rs5c372 *rs5c372; + struct rtc_time tm; dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); @@ -211,7 +510,15 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) err = -ENOMEM; goto exit; } - client = &rs5c372->client; + + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ + rs5c372->regs=&rs5c372->buf[1]; + + /* On conversion to a "new style" i2c driver, we'll be handed + * the i2c_client (we won't create it) + */ + client = &rs5c372->dev; + rs5c372->client = client; /* I2C client */ client->addr = address; @@ -222,16 +529,99 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) i2c_set_clientdata(client, rs5c372); - rs5c372->msg[0].addr = address; - rs5c372->msg[0].flags = I2C_M_RD; - rs5c372->msg[0].len = sizeof(rs5c372->regs); - rs5c372->msg[0].buf = rs5c372->regs; - /* Inform the i2c layer */ if ((err = i2c_attach_client(client))) goto exit_kfree; - dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + err = rs5c_get_regs(rs5c372); + if (err < 0) + goto exit_detach; + + /* For "new style" drivers, irq is in i2c_client and chip type + * info comes from i2c_client.dev.platform_data. Meanwhile: + * + * STICK BOARD-SPECIFIC SETUP CODE RIGHT HERE + */ + if (rs5c372->type == rtc_undef) { + 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: + case rtc_rs5c372b: + /* alarm uses ALARM_A; and nINTRA on 372a, nINTR on 372b. + * so does periodic irq, except some 327a modes. + */ + if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24) + rs5c372->time24 = 1; + break; + case rtc_rv5c386: + case rtc_rv5c387a: + if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24) + rs5c372->time24 = 1; + /* alarm uses ALARM_W; and nINTRB for alarm and periodic + * irq, on both 386 and 387 + */ + break; + default: + dev_err(&client->dev, "unknown RTC type\n"); + goto exit_detach; + } + + /* if the oscillator lost power and no other software (like + * the bootloader) set it up, do it here. + */ + if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) { + unsigned char buf[3]; + + rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP; + + buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); + buf[1] = rs5c372->regs[RS5C_REG_CTRL1]; + buf[2] = rs5c372->regs[RS5C_REG_CTRL2]; + + /* use 24hr mode */ + switch (rs5c372->type) { + case rtc_rs5c372a: + case rtc_rs5c372b: + buf[2] |= RS5C372_CTRL2_24; + rs5c372->time24 = 1; + break; + case rtc_rv5c386: + case rtc_rv5c387a: + buf[1] |= RV5C387_CTRL1_24; + rs5c372->time24 = 1; + break; + default: + /* impossible */ + break; + } + + if ((i2c_master_send(client, buf, 3)) != 3) { + dev_err(&client->dev, "setup error\n"); + goto exit_detach; + } + rs5c372->regs[RS5C_REG_CTRL1] = buf[1]; + rs5c372->regs[RS5C_REG_CTRL2] = buf[2]; + } + + if (rs5c372_get_datetime(client, &tm) < 0) + dev_warn(&client->dev, "clock needs to be set\n"); + + dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n", + ({ char *s; switch (rs5c372->type) { + case rtc_rs5c372a: s = "rs5c372a"; break; + case rtc_rs5c372b: s = "rs5c372b"; break; + case rtc_rv5c386: s = "rv5c386"; break; + case rtc_rv5c387a: s = "rv5c387a"; break; + default: s = "chip"; break; + }; s;}), + rs5c372->time24 ? "24hr" : "am/pm" + ); + + /* FIXME when client->irq exists, use it to register alarm irq */ rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name, &client->dev, &rs5c372_rtc_ops, THIS_MODULE); @@ -241,18 +631,12 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; } - err = device_create_file(&client->dev, &dev_attr_trim); + err = rs5c_sysfs_register(&client->dev); if (err) goto exit_devreg; - err = device_create_file(&client->dev, &dev_attr_osc); - if (err) - goto exit_trim; return 0; -exit_trim: - device_remove_file(&client->dev, &dev_attr_trim); - exit_devreg: rtc_device_unregister(rs5c372->rtc); @@ -266,6 +650,11 @@ exit: return err; } +static int rs5c372_attach(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, rs5c372_probe); +} + static int rs5c372_detach(struct i2c_client *client) { int err; @@ -274,6 +663,8 @@ static int rs5c372_detach(struct i2c_client *client) if (rs5c372->rtc) rtc_device_unregister(rs5c372->rtc); + /* REVISIT properly destroy the sysfs files ... */ + if ((err = i2c_detach_client(client))) return err; @@ -281,6 +672,14 @@ static int rs5c372_detach(struct i2c_client *client) return 0; } +static struct i2c_driver rs5c372_driver = { + .driver = { + .name = "rtc-rs5c372", + }, + .attach_adapter = &rs5c372_attach, + .detach_client = &rs5c372_detach, +}; + static __init int rs5c372_init(void) { return i2c_add_driver(&rs5c372_driver); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 72ba1a70f35..198b9f22fbf 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -264,8 +264,6 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq) unsigned int tmp; tmp = readb(rtc->regbase + RCR1); - seq_printf(seq, "alarm_IRQ\t: %s\n", - (tmp & RCR1_AIE) ? "yes" : "no"); seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no"); @@ -428,6 +426,8 @@ static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ tm->tm_year = 0xffff; + wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0; + spin_unlock_irq(&rtc->lock); return 0; @@ -492,10 +492,10 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) spin_lock_irq(&rtc->lock); - /* disable alarm interrupt and clear flag */ + /* disable alarm interrupt and clear the alarm flag */ rcr1 = readb(rtc->regbase + RCR1); - rcr1 &= ~RCR1_AF; - writeb(rcr1 & ~RCR1_AIE, rtc->regbase + RCR1); + rcr1 &= ~(RCR1_AF|RCR1_AIE); + writeb(rcr1, rtc->regbase + RCR1); rtc->rearm_aie = 0; @@ -510,8 +510,10 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) mon += 1; sh_rtc_write_alarm_value(rtc, mon, RMONAR); - /* Restore interrupt activation status */ - writeb(rcr1, rtc->regbase + RCR1); + if (wkalrm->enabled) { + rcr1 |= RCR1_AIE; + writeb(rcr1, rtc->regbase + RCR1); + } spin_unlock_irq(&rtc->lock); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 9418a59fb36..2ddd0cf0714 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -78,7 +78,7 @@ static struct attribute_group rtc_attr_group = { .attrs = rtc_attrs, }; -static int __devinit rtc_sysfs_add_device(struct class_device *class_dev, +static int rtc_sysfs_add_device(struct class_device *class_dev, struct class_interface *class_intf) { int err; diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index b9b0fc3f812..cdb24f52811 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -23,7 +23,7 @@ #include <asm/appldata.h> #include <asm/monwriter.h> -#define MONWRITE_MAX_DATALEN 4024 +#define MONWRITE_MAX_DATALEN 4010 static int mon_max_bufs = 255; static int mon_buf_count; diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 1678b6c757e..a420cd09904 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -117,7 +117,7 @@ vmcp_write(struct file *file, const char __user * buff, size_t count, return -ENOMEM; } debug_text_event(vmcp_debug, 1, cmd); - session->resp_size = __cpcmd(cmd, session->response, + session->resp_size = cpcmd(cmd, session->response, session->bufsize, &session->resp_code); up(&session->mutex); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 3a403f195cf..ae1bf231d08 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -2,8 +2,7 @@ * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls * - * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation + * Copyright (C) IBM Corp. 1999,2006 * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -886,6 +885,10 @@ static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr) s390_reset_pgm_handler = cio_reset_pgm_check_handler; rc = stsch(schid, addr); s390_reset_pgm_handler = NULL; + + /* The program check handler could have changed pgm_check_occured */ + barrier(); + if (pgm_check_occured) return -EIO; else diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 1a93fa684e9..52625153a4f 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -27,10 +27,7 @@ config IUCV help Select this option if you want to use inter-user communication under VM or VIF. If unsure, say "Y" to enable a fast communication - link between VM guests. At boot time the user ID of the guest needs - to be passed to the kernel. Note that both kernels need to be - compiled with this option and both need to be booted with the user ID - of the other VM guest. + link between VM guests. config NETIUCV tristate "IUCV network device support (VM only)" diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 53c358c7d36..e95c281f1e3 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -710,7 +710,7 @@ struct qeth_reply { int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long); u32 seqno; unsigned long offset; - int received; + atomic_t received; int rc; void *param; struct qeth_card *card; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 2bde4f1fb9c..d2efa5ff125 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -471,7 +471,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) channel->state == CH_STATE_UP) qeth_issue_next_read(card); - tasklet_schedule(&channel->irq_tasklet); + qeth_irq_tasklet((unsigned long)channel); return; out: wake_up(&card->wait_q); @@ -951,40 +951,6 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread) } static int -qeth_register_ip_addresses(void *ptr) -{ - struct qeth_card *card; - - card = (struct qeth_card *) ptr; - daemonize("qeth_reg_ip"); - QETH_DBF_TEXT(trace,4,"regipth1"); - if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD)) - return 0; - QETH_DBF_TEXT(trace,4,"regipth2"); - qeth_set_ip_addr_list(card); - qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD); - return 0; -} - -/* - * Drive the SET_PROMISC_MODE thread - */ -static int -qeth_set_promisc_mode(void *ptr) -{ - struct qeth_card *card = (struct qeth_card *) ptr; - - daemonize("qeth_setprm"); - QETH_DBF_TEXT(trace,4,"setprm1"); - if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD)) - return 0; - QETH_DBF_TEXT(trace,4,"setprm2"); - qeth_setadp_promisc_mode(card); - qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD); - return 0; -} - -static int qeth_recover(void *ptr) { struct qeth_card *card; @@ -1047,11 +1013,6 @@ qeth_start_kernel_thread(struct work_struct *work) if (card->read.state != CH_STATE_UP && card->write.state != CH_STATE_UP) return; - - if (qeth_do_start_thread(card, QETH_SET_IP_THREAD)) - kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD); - if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD)) - kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD); if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) kernel_thread(qeth_recover, (void *) card, SIGCHLD); } @@ -1074,7 +1035,7 @@ qeth_set_intial_options(struct qeth_card *card) card->options.layer2 = 1; else card->options.layer2 = 0; - card->options.performance_stats = 1; + card->options.performance_stats = 0; } /** @@ -1613,8 +1574,6 @@ qeth_issue_next_read(struct qeth_card *card) return -ENOMEM; } qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE); - wait_event(card->wait_q, - atomic_cmpxchg(&card->read.irq_pending, 0, 1) == 0); QETH_DBF_TEXT(trace, 6, "noirqpnd"); rc = ccw_device_start(card->read.ccwdev, &card->read.ccw, (addr_t) iob, 0, 0); @@ -1635,6 +1594,7 @@ qeth_alloc_reply(struct qeth_card *card) reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC); if (reply){ atomic_set(&reply->refcnt, 1); + atomic_set(&reply->received, 0); reply->card = card; }; return reply; @@ -1655,31 +1615,6 @@ qeth_put_reply(struct qeth_reply *reply) kfree(reply); } -static void -qeth_cmd_timeout(unsigned long data) -{ - struct qeth_reply *reply, *list_reply, *r; - unsigned long flags; - - reply = (struct qeth_reply *) data; - spin_lock_irqsave(&reply->card->lock, flags); - list_for_each_entry_safe(list_reply, r, - &reply->card->cmd_waiter_list, list) { - if (reply == list_reply){ - qeth_get_reply(reply); - list_del_init(&reply->list); - spin_unlock_irqrestore(&reply->card->lock, flags); - reply->rc = -ETIME; - reply->received = 1; - wake_up(&reply->wait_q); - qeth_put_reply(reply); - return; - } - } - spin_unlock_irqrestore(&reply->card->lock, flags); -} - - static struct qeth_ipa_cmd * qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) { @@ -1745,7 +1680,7 @@ qeth_clear_ipacmd_list(struct qeth_card *card) list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { qeth_get_reply(reply); reply->rc = -EIO; - reply->received = 1; + atomic_inc(&reply->received); list_del_init(&reply->list); wake_up(&reply->wait_q); qeth_put_reply(reply); @@ -1814,7 +1749,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel, &card->cmd_waiter_list); spin_unlock_irqrestore(&card->lock, flags); } else { - reply->received = 1; + atomic_inc(&reply->received); wake_up(&reply->wait_q); } qeth_put_reply(reply); @@ -1858,7 +1793,7 @@ qeth_send_control_data(struct qeth_card *card, int len, int rc; unsigned long flags; struct qeth_reply *reply = NULL; - struct timer_list timer; + unsigned long timeout; QETH_DBF_TEXT(trace, 2, "sendctl"); @@ -1873,21 +1808,20 @@ qeth_send_control_data(struct qeth_card *card, int len, reply->seqno = QETH_IDX_COMMAND_SEQNO; else reply->seqno = card->seqno.ipa++; - init_timer(&timer); - timer.function = qeth_cmd_timeout; - timer.data = (unsigned long) reply; init_waitqueue_head(&reply->wait_q); spin_lock_irqsave(&card->lock, flags); list_add_tail(&reply->list, &card->cmd_waiter_list); spin_unlock_irqrestore(&card->lock, flags); QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); - wait_event(card->wait_q, - atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0); + + while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; qeth_prepare_control_data(card, len, iob); + if (IS_IPA(iob->data)) - timer.expires = jiffies + QETH_IPA_TIMEOUT; + timeout = jiffies + QETH_IPA_TIMEOUT; else - timer.expires = jiffies + QETH_TIMEOUT; + timeout = jiffies + QETH_TIMEOUT; + QETH_DBF_TEXT(trace, 6, "noirqpnd"); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, @@ -1906,9 +1840,16 @@ qeth_send_control_data(struct qeth_card *card, int len, wake_up(&card->wait_q); return rc; } - add_timer(&timer); - wait_event(reply->wait_q, reply->received); - del_timer_sync(&timer); + while (!atomic_read(&reply->received)) { + if (time_after(jiffies, timeout)) { + spin_lock_irqsave(&reply->card->lock, flags); + list_del_init(&reply->list); + spin_unlock_irqrestore(&reply->card->lock, flags); + reply->rc = -ETIME; + atomic_inc(&reply->received); + wake_up(&reply->wait_q); + } + }; rc = reply->rc; qeth_put_reply(reply); return rc; @@ -2466,32 +2407,17 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, qeth_rebuild_skb_fake_ll_eth(card, skb, hdr); } -static inline __u16 +static inline void qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { - unsigned short vlan_id = 0; -#ifdef CONFIG_QETH_VLAN - struct vlan_hdr *vhdr; -#endif - skb->pkt_type = PACKET_HOST; skb->protocol = qeth_type_trans(skb, skb->dev); if (card->options.checksum_type == NO_CHECKSUMMING) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; -#ifdef CONFIG_QETH_VLAN - if (hdr->hdr.l2.flags[2] & (QETH_LAYER2_FLAG_VLAN)) { - vhdr = (struct vlan_hdr *) skb->data; - skb->protocol = - __constant_htons(vhdr->h_vlan_encapsulated_proto); - vlan_id = hdr->hdr.l2.vlan_id; - skb_pull(skb, VLAN_HLEN); - } -#endif *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; - return vlan_id; } static inline __u16 @@ -2560,7 +2486,6 @@ qeth_process_inbound_buffer(struct qeth_card *card, int offset; int rxrc; __u16 vlan_tag = 0; - __u16 *vlan_addr; /* get first element of current buffer */ element = (struct qdio_buffer_element *)&buf->buffer->element[0]; @@ -2571,7 +2496,7 @@ qeth_process_inbound_buffer(struct qeth_card *card, &offset, &hdr))) { skb->dev = card->dev; if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) - vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); + qeth_layer2_rebuild_skb(card, skb, hdr); else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) vlan_tag = qeth_rebuild_skb(card, skb, hdr); else { /*in case of OSN*/ @@ -3968,13 +3893,22 @@ static inline struct sk_buff * qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr **hdr, int ipv) { - struct sk_buff *new_skb; + struct sk_buff *new_skb, *new_skb2; QETH_DBF_TEXT(trace, 6, "prepskb"); - - new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); - if (new_skb == NULL) + new_skb = skb; + new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC); + if (!new_skb) + return NULL; + new_skb2 = qeth_realloc_headroom(card, new_skb, + sizeof(struct qeth_hdr)); + if (!new_skb2) { + __qeth_free_new_skb(skb, new_skb); return NULL; + } + if (new_skb != skb) + __qeth_free_new_skb(new_skb2, new_skb); + new_skb = new_skb2; *hdr = __qeth_prepare_skb(card, new_skb, ipv); if (*hdr == NULL) { __qeth_free_new_skb(skb, new_skb); @@ -4844,9 +4778,11 @@ qeth_arp_query(struct qeth_card *card, char __user *udata) "(0x%x/%d)\n", QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc), tmp, tmp); - copy_to_user(udata, qinfo.udata, 4); + if (copy_to_user(udata, qinfo.udata, 4)) + rc = -EFAULT; } else { - copy_to_user(udata, qinfo.udata, qinfo.udata_len); + if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) + rc = -EFAULT; } kfree(qinfo.udata); return rc; @@ -4992,8 +4928,10 @@ qeth_snmp_command(struct qeth_card *card, char __user *udata) if (rc) PRINT_WARN("SNMP command failed on %s: (0x%x)\n", QETH_CARD_IFNAME(card), rc); - else - copy_to_user(udata, qinfo.udata, qinfo.udata_len); + else { + if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) + rc = -EFAULT; + } kfree(ureq); kfree(qinfo.udata); @@ -5544,12 +5482,10 @@ qeth_set_multicast_list(struct net_device *dev) qeth_add_multicast_ipv6(card); #endif out: - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) return; - if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0) - schedule_work(&card->kernel_thread_starter); + qeth_setadp_promisc_mode(card); } static int @@ -6351,6 +6287,42 @@ static struct ethtool_ops qeth_ethtool_ops = { }; static int +qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + struct qeth_card *card; + struct ethhdr *eth; + + card = qeth_get_card_from_dev(skb->dev); + if (card->options.layer2) + goto haveheader; +#ifdef CONFIG_QETH_IPV6 + /* cause of the manipulated arp constructor and the ARP + flag for OSAE devices we have some nasty exceptions */ + if (card->info.type == QETH_CARD_TYPE_OSAE) { + if (!card->options.fake_ll) { + if ((skb->pkt_type==PACKET_OUTGOING) && + (skb->protocol==ETH_P_IPV6)) + goto haveheader; + else + return 0; + } else { + if ((skb->pkt_type==PACKET_OUTGOING) && + (skb->protocol==ETH_P_IP)) + return 0; + else + goto haveheader; + } + } +#endif + if (!card->options.fake_ll) + return 0; +haveheader: + eth = eth_hdr(skb); + memcpy(haddr, eth->h_source, ETH_ALEN); + return ETH_ALEN; +} + +static int qeth_netdev_init(struct net_device *dev) { struct qeth_card *card; @@ -6388,7 +6360,10 @@ qeth_netdev_init(struct net_device *dev) if (card->options.fake_ll && (qeth_get_netdev_flags(card) & IFF_NOARP)) dev->hard_header = qeth_fake_header; - dev->hard_header_parse = NULL; + if (dev->type == ARPHRD_IEEE802_TR) + dev->hard_header_parse = NULL; + else + dev->hard_header_parse = qeth_hard_header_parse; dev->set_mac_address = qeth_layer2_set_mac_address; dev->flags |= qeth_get_netdev_flags(card); if ((card->options.fake_broadcast) || @@ -8235,8 +8210,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, } if (!qeth_add_ip(card, ipaddr)) kfree(ipaddr); - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); return rc; } @@ -8264,8 +8238,7 @@ qeth_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto, return; if (!qeth_delete_ip(card, ipaddr)) kfree(ipaddr); - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); } /* @@ -8308,8 +8281,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, } if (!qeth_add_ip(card, ipaddr)) kfree(ipaddr); - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); return 0; } @@ -8337,8 +8309,7 @@ qeth_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto, return; if (!qeth_delete_ip(card, ipaddr)) kfree(ipaddr); - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); } /** @@ -8380,8 +8351,7 @@ qeth_ip_event(struct notifier_block *this, default: break; } - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); out: return NOTIFY_DONE; } @@ -8433,8 +8403,7 @@ qeth_ip6_event(struct notifier_block *this, default: break; } - if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + qeth_set_ip_addr_list(card); out: return NOTIFY_DONE; } diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 99a259c5a0c..e1b44d6c0c3 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2005 3ware Inc. + Copyright (C) 1999-2007 3ware Inc. Kernel compatiblity By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> @@ -191,6 +191,9 @@ before shutting down card. Change to new 'change_queue_depth' api. Fix 'handled=1' ISR usage, remove bogus IRQ check. + 1.26.02.002 - Free irq handler in __tw_shutdown(). + Turn on RCD bit for caching mode page. + Serialize reset code. */ #include <linux/module.h> @@ -214,7 +217,7 @@ #include "3w-xxxx.h" /* Globals */ -#define TW_DRIVER_VERSION "1.26.02.001" +#define TW_DRIVER_VERSION "1.26.02.002" static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; static int tw_device_extension_count = 0; static int twe_major = -1; @@ -226,7 +229,7 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(TW_DRIVER_VERSION); /* Function prototypes */ -static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset); +static int tw_reset_device_extension(TW_Device_Extension *tw_dev); /* Functions */ @@ -984,24 +987,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int /* Now wait for the command to complete */ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); - /* See if we reset while waiting for the ioctl to complete */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) { - clear_bit(TW_IN_RESET, &tw_dev->flags); - retval = -ERESTARTSYS; - goto out2; - } - /* We timed out, and didn't get an interrupt */ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { /* Now we need to reset the board */ printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd); retval = -EIO; - spin_lock_irqsave(tw_dev->host->host_lock, flags); - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->posted_request_count--; - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - if (tw_reset_device_extension(tw_dev, 1)) { + if (tw_reset_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no); } goto out2; @@ -1336,7 +1327,7 @@ static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) } /* End tw_unmap_scsi_data() */ /* This function will reset a device extension */ -static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) +static int tw_reset_device_extension(TW_Device_Extension *tw_dev) { int i = 0; struct scsi_cmnd *srb; @@ -1382,15 +1373,10 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_rese printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); return 1; } - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); - /* Wake up any ioctl that was pending before the reset */ - if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) { - clear_bit(TW_IN_RESET, &tw_dev->flags); - } else { - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - wake_up(&tw_dev->ioctl_wqueue); - } + TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); + clear_bit(TW_IN_RESET, &tw_dev->flags); + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; return 0; } /* End tw_reset_device_extension() */ @@ -1437,14 +1423,18 @@ static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) "WARNING: Command (0x%x) timed out, resetting card.\n", SCpnt->cmnd[0]); + /* Make sure we are not issuing an ioctl or resetting from ioctl */ + mutex_lock(&tw_dev->ioctl_lock); + /* Now reset the card and some of the device extension data */ - if (tw_reset_device_extension(tw_dev, 0)) { + if (tw_reset_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); goto out; } retval = SUCCESS; out: + mutex_unlock(&tw_dev->ioctl_lock); return retval; } /* End tw_scsi_eh_reset() */ @@ -1660,9 +1650,9 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques request_buffer[4] = 0x8; /* caching page */ request_buffer[5] = 0xa; /* page length */ if (*flags & 0x1) - request_buffer[6] = 0x4; /* WCE on */ + request_buffer[6] = 0x5; /* WCE on, RCD on */ else - request_buffer[6] = 0x0; /* WCE off */ + request_buffer[6] = 0x1; /* WCE off, RCD on */ tw_transfer_internal(tw_dev, request_id, request_buffer, sizeof(request_buffer)); @@ -2012,6 +2002,10 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd int retval = 1; TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + /* If we are resetting due to timed out ioctl, report as busy */ + if (test_bit(TW_IN_RESET, &tw_dev->flags)) + return SCSI_MLQUEUE_HOST_BUSY; + /* Save done function into Scsi_Cmnd struct */ SCpnt->scsi_done = done; @@ -2100,6 +2094,10 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance) handled = 1; + /* If we are resetting, bail */ + if (test_bit(TW_IN_RESET, &tw_dev->flags)) + goto tw_interrupt_bail; + /* Check controller for errors */ if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); @@ -2276,6 +2274,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev) /* Disable interrupts */ TW_DISABLE_INTERRUPTS(tw_dev); + /* Free up the IRQ */ + free_irq(tw_dev->tw_pci_dev->irq, tw_dev); + printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no); /* Tell the card we are shutting down */ @@ -2444,9 +2445,6 @@ static void tw_remove(struct pci_dev *pdev) twe_major = -1; } - /* Free up the IRQ */ - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - /* Shutdown the card */ __tw_shutdown(tw_dev); diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index bbd654a2b9b..0742e684665 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2005 3ware Inc. + Copyright (C) 1999-2007 3ware Inc. Kernel compatiblity By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 60f58272718..7869c34a4a3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1303,7 +1303,7 @@ config SCSI_LPFC config SCSI_SEAGATE tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" - depends on X86 && ISA && SCSI && BROKEN + depends on X86 && ISA && SCSI ---help--- These are 8-bit SCSI controllers; the ST-01 is also supported by this driver. It is explained in section 3.9 of the SCSI-HOWTO, diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 359e7ddfdb4..d2cf875af59 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -117,8 +117,8 @@ static struct pci_device_id aac_pci_tbl[] = { { 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */ { 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */ { 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */ - { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024R0 (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014R0 (Lancer) */ + { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024RO (Lancer) */ + { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014RO (Lancer) */ { 0x9005, 0x0286, 0x9005, 0x02a0, 0, 0, 27 }, /* ICP9047MA (Lancer) */ { 0x9005, 0x0286, 0x9005, 0x02a1, 0, 0, 28 }, /* ICP9087MA (Lancer) */ { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5445AU (Hurricane44) */ @@ -137,15 +137,15 @@ static struct pci_device_id aac_pci_tbl[] = { { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */ { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */ - { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */ + { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005 */ { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */ { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */ { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */ { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */ - { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */ + { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000 (BlackBird) */ { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */ { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */ - { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-3800SAS (Hurricane44) */ + { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-3800 (Hurricane44) */ { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/ { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/ @@ -193,8 +193,8 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2820SA ", 1 }, /* AAR-2820SA (Intruder) */ { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2620SA ", 1 }, /* AAR-2620SA (Intruder) */ { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2420SA ", 1 }, /* AAR-2420SA (Intruder) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9024R0 ", 2 }, /* ICP9024R0 (Lancer) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9014R0 ", 1 }, /* ICP9014R0 (Lancer) */ + { aac_rkt_init, "aacraid", "ICP ", "ICP9024RO ", 2 }, /* ICP9024RO (Lancer) */ + { aac_rkt_init, "aacraid", "ICP ", "ICP9014RO ", 1 }, /* ICP9014RO (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP5445AU ", 1 }, /* ICP5445AU (Hurricane44) */ @@ -212,14 +212,14 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2026ZCR ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2610SA ", 1 }, /* SATA 6Ch (Bearcat) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005 ", 1 }, /* ASR-4005 */ { aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */ { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */ { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000 ", 1 }, /* ASR-4000 (BlackBird & AvonPark) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-3800SAS ", 1 }, /* ASR-3800SAS (Hurricane44) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-3800 ", 1 }, /* ASR-3800 (Hurricane44) */ { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 2b344356a29..306bec355e4 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -18215,6 +18215,7 @@ AdvInquiryHandling( } MODULE_LICENSE("Dual BSD/GPL"); +#ifdef CONFIG_PCI /* PCI Devices supported by this driver */ static struct pci_device_id advansys_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A, @@ -18232,4 +18233,4 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = { { } }; MODULE_DEVICE_TABLE(pci, advansys_pci_tbl); - +#endif /* CONFIG_PCI */ diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index 6ac0633d545..f67d9efc7a9 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -1,7 +1,9 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o ibmvscsic-y += ibmvscsi.o +ifndef CONFIG_PPC_PSERIES ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o +endif ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index d0b139cccbb..43768408437 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -749,7 +749,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) if (!offset) crypto_hash_update( &tcp_conn->rx_hash, - &sg[i], 1); + &sg[i], sg[i].length); else partial_sg_digest_update( &tcp_conn->rx_hash, @@ -1777,13 +1777,13 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->tx_hash.flags = 0; - if (!tcp_conn->tx_hash.tfm) + if (IS_ERR(tcp_conn->tx_hash.tfm)) goto free_tcp_conn; tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->rx_hash.flags = 0; - if (!tcp_conn->rx_hash.tfm) + if (IS_ERR(tcp_conn->rx_hash.tfm)) goto free_tx_tfm; return cls_conn; @@ -2044,13 +2044,11 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, sk = tcp_conn->sock->sk; if (sk->sk_family == PF_INET) { inet = inet_sk(sk); - len = sprintf(buf, "%u.%u.%u.%u\n", + len = sprintf(buf, NIPQUAD_FMT "\n", NIPQUAD(inet->daddr)); } else { np = inet6_sk(sk); - len = sprintf(buf, - "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - NIP6(np->daddr)); + len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); } mutex_unlock(&conn->xmitmutex); break; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index e11b23c641e..d37048c96ea 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -260,7 +260,7 @@ static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) { - int senselen; + uint16_t senselen; if (datalen < 2) { invalid_datalen: @@ -270,12 +270,12 @@ invalid_datalen: goto out; } - senselen = (data[0] << 8) | data[1]; + senselen = be16_to_cpu(*(uint16_t *)data); if (datalen < senselen) goto invalid_datalen; memcpy(sc->sense_buffer, data + 2, - min(senselen, SCSI_SENSE_BUFFERSIZE)); + min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); debug_scsi("copied %d bytes of sense\n", min(senselen, SCSI_SENSE_BUFFERSIZE)); } diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 066292d3995..ec3bbbde6f7 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -56,6 +56,9 @@ lpfc_mem_alloc(struct lpfc_hba * phba) pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) * LPFC_MBUF_POOL_SIZE, GFP_KERNEL); + if (!pool->elements) + goto fail_free_lpfc_mbuf_pool; + pool->max_count = 0; pool->current_count = 0; for ( i = 0; i < LPFC_MBUF_POOL_SIZE; i++) { @@ -82,10 +85,11 @@ lpfc_mem_alloc(struct lpfc_hba * phba) fail_free_mbox_pool: mempool_destroy(phba->mbox_mem_pool); fail_free_mbuf_pool: - while (--i) + while (i--) pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt, pool->elements[i].phys); kfree(pool->elements); + fail_free_lpfc_mbuf_pool: pci_pool_destroy(phba->lpfc_mbuf_pool); fail_free_dma_buf_pool: pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 046223b4ae5..b5bdd0d7a8b 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -13,8 +13,8 @@ * Version : v00.00.03.05 * * Authors: - * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com> - * Sumant Patro <Sumant.Patro@lsil.com> + * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com> + * Sumant Patro <Sumant.Patro@lsi.com> * * List of supported controllers * @@ -45,7 +45,7 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(MEGASAS_VERSION); -MODULE_AUTHOR("sreenivas.bagalkote@lsil.com"); +MODULE_AUTHOR("megaraidlinux@lsi.com"); MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver"); /* diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index d72df5dae4e..e16fe361436 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1629,7 +1629,6 @@ static int nsp_cs_probe(struct pcmcia_device *link) /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; ret = nsp_cs_config(link); diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index fb7acea6028..5b458d2478f 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -545,8 +545,6 @@ SYM53C500_release(struct pcmcia_device *link) */ if (shost->irq) free_irq(shost->irq, shost); - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); @@ -895,7 +893,6 @@ SYM53C500_probe(struct pcmcia_device *link) link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; return SYM53C500_config(link); } /* SYM53C500_attach */ diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 16af5b79e58..1548d42a3b4 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1341,7 +1341,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) int host_status = DID_ERROR; uint16_t comp_status = le16_to_cpu(sts->comp_status); uint16_t state_flags = le16_to_cpu(sts->state_flags); - uint16_t residual_length = le32_to_cpu(sts->residual_length); + uint32_t residual_length = le32_to_cpu(sts->residual_length); uint16_t scsi_status = le16_to_cpu(sts->scsi_status); #if DEBUG_QLA1280_INTR static char *reason[] = { @@ -1413,8 +1413,10 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) "scsi: Underflow detected - retrying " "command.\n"); host_status = DID_ERROR; - } else + } else { + cp->resid = residual_length; host_status = DID_OK; + } break; default: diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c4fc40f8e8c..2c10130d9e0 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1602,6 +1602,7 @@ typedef struct fc_port { #define CT_REJECT_RESPONSE 0x8001 #define CT_ACCEPT_RESPONSE 0x8002 +#define CT_REASON_INVALID_COMMAND_CODE 0x01 #define CT_REASON_CANNOT_PERFORM 0x09 #define CT_EXPL_ALREADY_REGISTERED 0x10 @@ -2079,6 +2080,7 @@ typedef struct scsi_qla_host { uint32_t msi_enabled :1; uint32_t msix_enabled :1; uint32_t disable_serdes :1; + uint32_t gpsc_supported :1; } flags; atomic_t loop_state; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 32ebeec45ff..e4dd12f4b80 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -45,7 +45,6 @@ extern void qla2x00_update_fcports(scsi_qla_host_t *); extern int qla2x00_abort_isp(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); -extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 97fbc62ec66..ec5b2dd90d6 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -127,8 +127,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt, ha->host_no, routine, ms_pkt->entry_status)); } else { if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) - comp_status = - ((struct ct_entry_24xx *)ms_pkt)->comp_status; + comp_status = le16_to_cpu( + ((struct ct_entry_24xx *)ms_pkt)->comp_status); else comp_status = le16_to_cpu(ms_pkt->status); switch (comp_status) { @@ -143,6 +143,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt, DEBUG2_3(qla2x00_dump_buffer( (uint8_t *)&ct_rsp->header, sizeof(struct ct_rsp_hdr))); + rval = QLA_INVALID_COMMAND; } else rval = QLA_SUCCESS; break; @@ -1683,7 +1684,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list) memset(list[i].fabric_port_name, 0, WWN_SIZE); /* Prepare common MS IOCB */ - ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE, + ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GFPN_ID_REQ_SIZE, GFPN_ID_RSP_SIZE); /* Prepare CT request */ @@ -1784,6 +1785,8 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) return QLA_FUNCTION_FAILED; + if (!ha->flags.gpsc_supported) + return QLA_FUNCTION_FAILED; rval = qla2x00_mgmt_svr_login(ha); if (rval) @@ -1813,8 +1816,19 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) /*EMPTY*/ DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB " "failed (%d).\n", ha->host_no, rval)); - } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, - "GPSC") != QLA_SUCCESS) { + } else if ((rval = qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, + "GPSC")) != QLA_SUCCESS) { + /* FM command unsupported? */ + if (rval == QLA_INVALID_COMMAND && + ct_rsp->header.reason_code == + CT_REASON_INVALID_COMMAND_CODE) { + DEBUG2(printk("scsi(%ld): GPSC command " + "unsupported, disabling query...\n", + ha->host_no)); + ha->flags.gpsc_supported = 0; + rval = QLA_FUNCTION_FAILED; + break; + } rval = QLA_FUNCTION_FAILED; } else { /* Save portname */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index a823f0bc519..b3dac26ddba 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2103,40 +2103,7 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) } } -/* - * qla2x00_update_fcport - * Updates device on list. - * - * Input: - * ha = adapter block pointer. - * fcport = port structure pointer. - * - * Return: - * 0 - Success - * BIT_0 - error - * - * Context: - * Kernel context. - */ -void -qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) -{ - fcport->ha = ha; - fcport->login_retry = 0; - fcport->port_login_retry_count = ha->port_down_retry_count * - PORT_RETRY_TIME; - atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * - PORT_RETRY_TIME); - fcport->flags &= ~FCF_LOGIN_NEEDED; - - qla2x00_iidma_fcport(ha, fcport); - - atomic_set(&fcport->state, FCS_ONLINE); - - qla2x00_reg_remote_port(ha, fcport); -} - -void +static void qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) { struct fc_rport_identifiers rport_ids; @@ -2179,6 +2146,39 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) } /* + * qla2x00_update_fcport + * Updates device on list. + * + * Input: + * ha = adapter block pointer. + * fcport = port structure pointer. + * + * Return: + * 0 - Success + * BIT_0 - error + * + * Context: + * Kernel context. + */ +void +qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) +{ + fcport->ha = ha; + fcport->login_retry = 0; + fcport->port_login_retry_count = ha->port_down_retry_count * + PORT_RETRY_TIME; + atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * + PORT_RETRY_TIME); + fcport->flags &= ~FCF_LOGIN_NEEDED; + + qla2x00_iidma_fcport(ha, fcport); + + atomic_set(&fcport->state, FCS_ONLINE); + + qla2x00_reg_remote_port(ha, fcport); +} + +/* * qla2x00_configure_fabric * Setup SNS devices with loop ID's. * @@ -3476,9 +3476,11 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) /* Set host adapter parameters. */ ha->flags.disable_risc_code_load = 0; - ha->flags.enable_lip_reset = 1; - ha->flags.enable_lip_full_login = 1; - ha->flags.enable_target_reset = 1; + ha->flags.enable_lip_reset = 0; + ha->flags.enable_lip_full_login = + le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; + ha->flags.enable_target_reset = + le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; ha->flags.enable_led_scheme = 0; ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d3b6df4d55c..39fd17b05be 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -134,11 +134,11 @@ qla2300_intr_handler(int irq, void *dev_id) if (stat & HSR_RISC_PAUSED) { hccr = RD_REG_WORD(®->hccr); if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) - qla_printk(KERN_INFO, ha, - "Parity error -- HCCR=%x.\n", hccr); + qla_printk(KERN_INFO, ha, "Parity error -- " + "HCCR=%x, Dumping firmware!\n", hccr); else - qla_printk(KERN_INFO, ha, - "RISC paused -- HCCR=%x.\n", hccr); + qla_printk(KERN_INFO, ha, "RISC paused -- " + "HCCR=%x, Dumping firmware!\n", hccr); /* * Issue a "HARD" reset in order for the RISC @@ -147,6 +147,8 @@ qla2300_intr_handler(int irq, void *dev_id) */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); RD_REG_WORD(®->hccr); + + ha->isp_ops.fw_dump(ha, 1); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; } else if ((stat & HSR_RISC_INT) == 0) @@ -475,6 +477,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); } set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); + + ha->flags.gpsc_supported = 1; break; case MBA_CHG_IN_CONNECTION: /* Change in connection mode */ @@ -1440,8 +1444,7 @@ qla24xx_intr_handler(int irq, void *dev_id) qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " "Dumping firmware!\n", hccr); - qla24xx_fw_dump(ha, 1); - + ha->isp_ops.fw_dump(ha, 1); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; } else if ((stat & HSRX_RISC_INT) == 0) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 4cde76c85cb..077e5789bee 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1339,9 +1339,9 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = BIT_0; - mcp->mb[2] = 0xff; - mcp->mb[3] = 0; + mcp->mb[1] = BIT_6; + mcp->mb[2] = 0; + mcp->mb[3] = ha->loop_reset_delay; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; } else { mcp->mb[0] = MBC_LIP_RESET; @@ -1823,8 +1823,8 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) ha->host_no)); mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = 0; - mcp->mb[2] = 0xff; + mcp->mb[1] = IS_QLA24XX(ha) || IS_QLA54XX(ha) ? BIT_3: 0; + mcp->mb[2] = 0; mcp->mb[3] = 0; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; @@ -2486,7 +2486,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, mcp->mb[4] = LSW(MSD(eft_dma)); mcp->mb[5] = MSW(MSD(eft_dma)); mcp->mb[6] = buffers; - mcp->mb[7] = buffers; + mcp->mb[7] = 0; mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2; } mcp->tov = 30; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d03523d3bf3..d6445ae841b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1037,48 +1037,49 @@ eh_host_reset_lock: static int qla2x00_loop_reset(scsi_qla_host_t *ha) { - int status = QLA_SUCCESS; + int ret; struct fc_port *fcport; + if (ha->flags.enable_lip_full_login) { + ret = qla2x00_full_login_lip(ha); + if (ret != QLA_SUCCESS) { + DEBUG2_3(printk("%s(%ld): bus_reset failed: " + "full_login_lip=%d.\n", __func__, ha->host_no, + ret)); + } + atomic_set(&ha->loop_state, LOOP_DOWN); + atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(ha, 0); + qla2x00_wait_for_loop_ready(ha); + } + if (ha->flags.enable_lip_reset) { - status = qla2x00_lip_reset(ha); + ret = qla2x00_lip_reset(ha); + if (ret != QLA_SUCCESS) { + DEBUG2_3(printk("%s(%ld): bus_reset failed: " + "lip_reset=%d.\n", __func__, ha->host_no, ret)); + } + qla2x00_wait_for_loop_ready(ha); } - if (status == QLA_SUCCESS && ha->flags.enable_target_reset) { + if (ha->flags.enable_target_reset) { list_for_each_entry(fcport, &ha->fcports, list) { if (fcport->port_type != FCT_TARGET) continue; - status = qla2x00_device_reset(ha, fcport); - if (status != QLA_SUCCESS) - break; + ret = qla2x00_device_reset(ha, fcport); + if (ret != QLA_SUCCESS) { + DEBUG2_3(printk("%s(%ld): bus_reset failed: " + "target_reset=%d d_id=%x.\n", __func__, + ha->host_no, ret, fcport->d_id.b24)); + } } } - if (status == QLA_SUCCESS && - ((!ha->flags.enable_target_reset && - !ha->flags.enable_lip_reset) || - ha->flags.enable_lip_full_login)) { - - status = qla2x00_full_login_lip(ha); - } - /* Issue marker command only when we are going to start the I/O */ ha->marker_needed = 1; - if (status) { - /* Empty */ - DEBUG2_3(printk("%s(%ld): **** FAILED ****\n", - __func__, - ha->host_no)); - } else { - /* Empty */ - DEBUG3(printk("%s(%ld): exiting normally.\n", - __func__, - ha->host_no)); - } - - return(status); + return QLA_SUCCESS; } /* @@ -1413,7 +1414,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) sht = &qla2x00_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432) + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432) sht = &qla24xx_driver_template; host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t)); if (host == NULL) { diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 1fa0bce6b24..459e0d6bd2b 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.07-k3" +#define QLA2XXX_VERSION "8.01.07-k4" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 4249e52a559..6f4cf2dd2f4 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -418,7 +418,6 @@ struct scsi_qla_host { * concurrently. */ struct mutex mbox_sem; - wait_queue_head_t mailbox_wait_queue; /* temporary mailbox status registers */ volatile uint8_t mbox_status_count; diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 2122967bbf0..e021eb5db2b 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -76,4 +76,5 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; extern int ql4xdontresethba; +extern int ql4_mod_unload; #endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index cc210f297a7..b907b06d72a 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -958,25 +958,25 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) return status; } -int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) +int ql4xxx_lock_drvr_wait(struct scsi_qla_host *ha) { -#define QL4_LOCK_DRVR_WAIT 300 -#define QL4_LOCK_DRVR_SLEEP 100 +#define QL4_LOCK_DRVR_WAIT 30 +#define QL4_LOCK_DRVR_SLEEP 1 int drvr_wait = QL4_LOCK_DRVR_WAIT; while (drvr_wait) { - if (ql4xxx_lock_drvr(a) == 0) { - msleep(QL4_LOCK_DRVR_SLEEP); + if (ql4xxx_lock_drvr(ha) == 0) { + ssleep(QL4_LOCK_DRVR_SLEEP); if (drvr_wait) { DEBUG2(printk("scsi%ld: %s: Waiting for " - "Global Init Semaphore...n", - a->host_no, - __func__)); + "Global Init Semaphore(%d)...n", + ha->host_no, + __func__, drvr_wait)); } drvr_wait -= QL4_LOCK_DRVR_SLEEP; } else { DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " - "acquired.n", a->host_no, __func__)); + "acquired.n", ha->host_no, __func__)); return QLA_SUCCESS; } } diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index ef975e0dc87..35b9e36a0e8 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -433,7 +433,6 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, readl(&ha->reg->mailbox[i]); set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); - wake_up(&ha->mailbox_wait_queue); } } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { /* Immediately process the AENs that don't require much work. @@ -686,7 +685,8 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); - set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); + if (!ql4_mod_unload) + set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); break; } else if (intr_status & INTR_PENDING) { diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index b721dc5dd71..7f28657eef3 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -29,18 +29,30 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, u_long wait_count; uint32_t intr_status; unsigned long flags = 0; - DECLARE_WAITQUEUE(wait, current); - - mutex_lock(&ha->mbox_sem); - - /* Mailbox code active */ - set_bit(AF_MBOX_COMMAND, &ha->flags); /* Make sure that pointers are valid */ if (!mbx_cmd || !mbx_sts) { DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " "pointer\n", ha->host_no, __func__)); - goto mbox_exit; + return status; + } + /* Mailbox code active */ + wait_count = MBOX_TOV * 100; + + while (wait_count--) { + mutex_lock(&ha->mbox_sem); + if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { + set_bit(AF_MBOX_COMMAND, &ha->flags); + mutex_unlock(&ha->mbox_sem); + break; + } + mutex_unlock(&ha->mbox_sem); + if (!wait_count) { + DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n", + ha->host_no, __func__)); + return status; + } + msleep(10); } /* To prevent overwriting mailbox registers for a command that has @@ -73,8 +85,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for completion */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&ha->mailbox_wait_queue, &wait); /* * If we don't want status, don't wait for the mailbox command to @@ -83,8 +93,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, */ if (outCount == 0) { status = QLA_SUCCESS; - set_current_state(TASK_RUNNING); - remove_wait_queue(&ha->mailbox_wait_queue, &wait); goto mbox_exit; } /* Wait for command to complete */ @@ -108,8 +116,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, spin_unlock_irqrestore(&ha->hardware_lock, flags); msleep(10); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&ha->mailbox_wait_queue, &wait); /* Check for mailbox timeout. */ if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { @@ -155,9 +161,10 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, spin_unlock_irqrestore(&ha->hardware_lock, flags); mbox_exit: + mutex_lock(&ha->mbox_sem); clear_bit(AF_MBOX_COMMAND, &ha->flags); - clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); mutex_unlock(&ha->mbox_sem); + clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); return status; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 9ef693c8809..81fb7bd44f0 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -40,6 +40,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging, 1 - debug logging"); +int ql4_mod_unload = 0; + /* * SCSI host template entry points */ @@ -422,6 +424,9 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, goto qc_host_busy; } + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) + goto qc_host_busy; + spin_unlock_irq(ha->host->host_lock); srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done); @@ -707,16 +712,12 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) return stat; } -/** - * qla4xxx_soft_reset - performs soft reset. - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_soft_reset(struct scsi_qla_host *ha) +static void qla4xxx_hw_reset(struct scsi_qla_host *ha) { - uint32_t max_wait_time; - unsigned long flags = 0; - int status = QLA_ERROR; uint32_t ctrl_status; + unsigned long flags = 0; + + DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -733,6 +734,20 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha) readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +/** + * qla4xxx_soft_reset - performs soft reset. + * @ha: Pointer to host adapter structure. + **/ +int qla4xxx_soft_reset(struct scsi_qla_host *ha) +{ + uint32_t max_wait_time; + unsigned long flags = 0; + int status = QLA_ERROR; + uint32_t ctrl_status; + + qla4xxx_hw_reset(ha); /* Wait until the Network Reset Intr bit is cleared */ max_wait_time = RESET_INTR_TOV; @@ -966,10 +981,12 @@ static void qla4xxx_do_dpc(struct work_struct *work) struct scsi_qla_host *ha = container_of(work, struct scsi_qla_host, dpc_work); struct ddb_entry *ddb_entry, *dtemp; + int status = QLA_ERROR; DEBUG2(printk("scsi%ld: %s: DPC handler waking up." - "flags = 0x%08lx, dpc_flags = 0x%08lx\n", - ha->host_no, __func__, ha->flags, ha->dpc_flags)); + "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n", + ha->host_no, __func__, ha->flags, ha->dpc_flags, + readw(&ha->reg->ctrl_status))); /* Initialization not yet finished. Don't do anything yet. */ if (!test_bit(AF_INIT_DONE, &ha->flags)) @@ -983,31 +1000,28 @@ static void qla4xxx_do_dpc(struct work_struct *work) test_bit(DPC_RESET_HA, &ha->dpc_flags)) qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); - if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { uint8_t wait_time = RESET_INTR_TOV; - unsigned long flags = 0; - - qla4xxx_flush_active_srbs(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); while ((readw(&ha->reg->ctrl_status) & (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { if (--wait_time == 0) break; - - spin_unlock_irqrestore(&ha->hardware_lock, - flags); - msleep(1000); - - spin_lock_irqsave(&ha->hardware_lock, flags); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (wait_time == 0) DEBUG2(printk("scsi%ld: %s: SR|FSR " "bit not cleared-- resetting\n", ha->host_no, __func__)); + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + status = qla4xxx_initialize_adapter(ha, + PRESERVE_DDB_LIST); + } + clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); + if (status == QLA_SUCCESS) + qla4xxx_enable_intrs(ha); } } @@ -1062,7 +1076,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) /* Issue Soft Reset to put firmware in unknown state */ if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) - qla4xxx_soft_reset(ha); + qla4xxx_hw_reset(ha); /* Remove timer thread, if present */ if (ha->timer_active) @@ -1198,7 +1212,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, INIT_LIST_HEAD(&ha->free_srb_q); mutex_init(&ha->mbox_sem); - init_waitqueue_head(&ha->mailbox_wait_queue); spin_lock_init(&ha->hardware_lock); @@ -1665,6 +1678,7 @@ no_srp_cache: static void __exit qla4xxx_module_exit(void) { + ql4_mod_unload = 1; pci_unregister_driver(&qla4xxx_pci_driver); iscsi_unregister_transport(&qla4xxx_iscsi_transport); kmem_cache_destroy(srb_cachep); diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 454e19c8ad6..e5183a697d1 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.00.07-k" +#define QLA4XXX_DRIVER_VERSION "5.00.07-k1" diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1748e27501c..f02f48a882a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -265,13 +265,11 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) if (!rq->bio) blk_rq_bio_prep(q, rq, bio); - else if (!q->back_merge_fn(q, rq, bio)) + else if (!ll_back_merge_fn(q, rq, bio)) return -EINVAL; else { rq->biotail->bi_next = bio; rq->biotail = bio; - rq->hard_nr_sectors += bio_sectors(bio); - rq->nr_sectors = rq->hard_nr_sectors; } return 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 14e635aa44c..96b7cbd746a 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -133,12 +133,10 @@ struct async_scan_data { /** * scsi_complete_async_scans - Wait for asynchronous scans to complete * - * Asynchronous scans add themselves to the scanning_hosts list. Once - * that list is empty, we know that the scans are complete. Rather than - * waking up periodically to check the state of the list, we pretend to be - * a scanning task by adding ourselves at the end of the list and going to - * sleep. When the task before us wakes us up, we take ourselves off the - * list and return. + * When this function returns, any host which started scanning before + * this function was called will have finished its scan. Hosts which + * started scanning after this function was called may or may not have + * finished. */ int scsi_complete_async_scans(void) { @@ -171,6 +169,11 @@ int scsi_complete_async_scans(void) spin_lock(&async_scan_lock); list_del(&data->list); + if (!list_empty(&scanning_hosts)) { + struct async_scan_data *next = list_entry(scanning_hosts.next, + struct async_scan_data, list); + complete(&next->prev_finished); + } done: spin_unlock(&async_scan_lock); @@ -739,6 +742,14 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->no_uld_attach = 1; switch (sdev->type = (inq_result[0] & 0x1f)) { + case TYPE_RBC: + /* RBC devices can return SCSI-3 compliance and yet + * still not support REPORT LUNS, so make them act as + * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is + * specifically set */ + if ((*bflags & BLIST_REPORTLUN2) == 0) + *bflags |= BLIST_NOREPORTLUN; + /* fall through */ case TYPE_TAPE: case TYPE_DISK: case TYPE_PRINTER: @@ -749,11 +760,17 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, case TYPE_ENCLOSURE: case TYPE_COMM: case TYPE_RAID: - case TYPE_RBC: sdev->writeable = 1; break; - case TYPE_WORM: case TYPE_ROM: + /* MMC devices can return SCSI-3 compliance and yet + * still not support REPORT LUNS, so make them act as + * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is + * specifically set */ + if ((*bflags & BLIST_REPORTLUN2) == 0) + *bflags |= BLIST_NOREPORTLUN; + /* fall through */ + case TYPE_WORM: sdev->writeable = 0; break; default: @@ -1436,6 +1453,12 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, struct device *parent = &shost->shost_gendev; struct scsi_target *starget; + if (strncmp(scsi_scan_type, "none", 4) == 0) + return ERR_PTR(-ENODEV); + + if (!shost->async_scan) + scsi_complete_async_scans(); + starget = scsi_alloc_target(parent, channel, id); if (!starget) return ERR_PTR(-ENOMEM); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9c22f134271..ce0d14af33c 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1416,7 +1416,7 @@ static __init int iscsi_transport_init(void) { int err; - printk(KERN_INFO "Loading iSCSI transport class v%s.", + printk(KERN_INFO "Loading iSCSI transport class v%s.\n", ISCSI_TRANSPORT_VERSION); err = class_register(&iscsi_transport_class); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 3fded483146..014d7fea1ff 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -122,7 +122,7 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd, if (!sshdr) sshdr = &sshdr_tmp; - if (scsi_normalize_sense(sense, sizeof(*sense), + if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr) && sshdr->sense_key == UNIT_ATTENTION) continue; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 978bfc1e0c6..b781a90d669 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1647,16 +1647,6 @@ static int sd_probe(struct device *dev) if (error) goto out_put; - class_device_initialize(&sdkp->cdev); - sdkp->cdev.dev = &sdp->sdev_gendev; - sdkp->cdev.class = &sd_disk_class; - strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); - - if (class_device_add(&sdkp->cdev)) - goto out_put; - - get_device(&sdp->sdev_gendev); - sdkp->device = sdp; sdkp->driver = &sd_template; sdkp->disk = gd; @@ -1670,6 +1660,16 @@ static int sd_probe(struct device *dev) sdp->timeout = SD_MOD_TIMEOUT; } + class_device_initialize(&sdkp->cdev); + sdkp->cdev.dev = &sdp->sdev_gendev; + sdkp->cdev.class = &sd_disk_class; + strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); + + if (class_device_add(&sdkp->cdev)) + goto out_put; + + get_device(&sdp->sdev_gendev); + gd->major = sd_major((index & 0xf0) >> 4); gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); gd->minors = 16; diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 5ffec2721b2..ff62e9708e1 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -114,6 +114,7 @@ #define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0) #else #define DPRINTK( when, msg... ) do { } while (0) +#define DEBUG 0 #endif #define DANY( msg... ) DPRINTK( 0xffff, msg ); @@ -523,7 +524,7 @@ int __init seagate_st0x_detect (struct scsi_host_template * tpnt) #ifdef ARBITRATE " ARBITRATE" #endif -#ifdef DEBUG +#if DEBUG " DEBUG" #endif #ifdef FAST @@ -733,7 +734,7 @@ static int internal_command (unsigned char target, unsigned char lun, unsigned char *data = NULL; struct scatterlist *buffer = NULL; int clock, temp, nobuffs = 0, done = 0, len = 0; -#ifdef DEBUG +#if DEBUG int transfered = 0, phase = 0, newphase; #endif register unsigned char status_read; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index fae6e95a629..89e9b36b178 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -468,7 +468,7 @@ static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd, } ret = cdrom_ioctl(file, &cd->cdi, inode, cmd, arg); - if (ret != ENOSYS) + if (ret != -ENOSYS) return ret; /* diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e016e0906e1..488ec7948a5 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -2816,15 +2816,18 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon if (cmd_in == MTWEOF && cmdstatp->have_sense && - (cmdstatp->flags & SENSE_EOM) && - (cmdstatp->sense_hdr.sense_key == NO_SENSE || - cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && - undone == 0) { - ioctl_result = 0; /* EOF written successfully at EOM */ - if (fileno >= 0) - fileno++; + (cmdstatp->flags & SENSE_EOM)) { + if (cmdstatp->sense_hdr.sense_key == NO_SENSE || + cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) { + ioctl_result = 0; /* EOF(s) written successfully at EOM */ + STps->eof = ST_NOEOF; + } else { /* Writing EOF(s) failed */ + if (fileno >= 0) + fileno -= undone; + if (undone < arg) + STps->eof = ST_NOEOF; + } STps->drv_file = fileno; - STps->eof = ST_NOEOF; } else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) { if (fileno >= 0) STps->drv_file = fileno - undone; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 51f3c739f7e..5261f0af8b1 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2296,7 +2296,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) local_irq_restore(flags); } -static int serial8250_console_setup(struct console *co, char *options) +static int __init serial8250_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 61db6973755..f69bd097166 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -589,6 +589,8 @@ static int __init pl010_console_setup(struct console *co, char *options) */ if (co->index >= UART_NR) co->index = 0; + if (!amba_ports[co->index]) + return -ENODEV; port = &amba_ports[co->index]->port; if (options) diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 9a3b374b2a0..44639e71372 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -661,6 +661,8 @@ static int __init pl011_console_setup(struct console *co, char *options) if (co->index >= UART_NR) co->index = 0; uap = amba_ports[co->index]; + if (!uap) + return -ENODEV; uap->port.uartclk = clk_get_rate(uap->clk); diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index ed7f7209ea5..881f886b91c 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -689,9 +689,9 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct struct atmel_uart_data *data = pdev->dev.platform_data; port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; + port->flags = UPF_BOOT_AUTOCONF; port->ops = &atmel_pops; - port->fifosize = 1; + port->fifosize = 1; port->line = pdev->id; port->dev = &pdev->dev; @@ -890,7 +890,6 @@ static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock()) enable_irq_wake(port->irq); else { - disable_irq_wake(port->irq); uart_suspend_port(&atmel_uart, port); atmel_port->suspended = 1; } @@ -907,6 +906,8 @@ static int atmel_serial_resume(struct platform_device *pdev) uart_resume_port(&atmel_uart, port); atmel_port->suspended = 0; } + else + disable_irq_wake(port->irq); return 0; } diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h index fe1763b2a6d..11b44360e10 100644 --- a/drivers/serial/atmel_serial.h +++ b/drivers/serial/atmel_serial.h @@ -106,7 +106,7 @@ #define ATMEL_US_CSR 0x14 /* Channel Status Register */ #define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ #define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ -#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [SAM9 only] */ +#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [AT91SAM9261 only] */ #define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ #define ATMEL_US_CD (0xffff << 0) /* Clock Divider */ diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 9d11a75663e..3c4b6c24371 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -789,7 +789,9 @@ static struct console mpc52xx_console = { static int __init mpc52xx_console_init(void) { +#if defined(CONFIG_PPC_MERGE) mpc52xx_uart_of_enumerate(); +#endif register_console(&mpc52xx_console); return 0; } diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 493d5bbb661..145d6236954 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -1037,7 +1037,8 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up, err = request_irq(up->port.irq, sunsab_interrupt, IRQF_SHARED, "sab", up); if (err) { - of_iounmap(up->port.membase, + of_iounmap(&op->resource[0], + up->port.membase, sizeof(union sab82532_async_regs)); return err; } @@ -1064,7 +1065,8 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id * sizeof(union sab82532_async_regs), (inst * 2) + 1); if (err) { - of_iounmap(up[0].port.membase, + of_iounmap(&op->resource[0], + up[0].port.membase, sizeof(union sab82532_async_regs)); free_irq(up[0].port.irq, &up[0]); return err; @@ -1082,10 +1084,13 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id * static void __devexit sab_remove_one(struct uart_sunsab_port *up) { + struct of_device *op = to_of_device(up->port.dev); + uart_remove_one_port(&sunsab_reg, &up->port); if (!(up->port.line & 1)) free_irq(up->port.irq, up); - of_iounmap(up->port.membase, + of_iounmap(&op->resource[0], + up->port.membase, sizeof(union sab82532_async_regs)); } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 564592b2b2b..3ec3df21816 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1480,13 +1480,13 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m return 0; out_unmap: - of_iounmap(up->port.membase, up->reg_size); + of_iounmap(&op->resource[0], up->port.membase, up->reg_size); return err; } -static int __devexit su_remove(struct of_device *dev) +static int __devexit su_remove(struct of_device *op) { - struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);; + struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); if (up->su_type == SU_PORT_MS || up->su_type == SU_PORT_KBD) { @@ -1499,9 +1499,9 @@ static int __devexit su_remove(struct of_device *dev) } if (up->port.membase) - of_iounmap(up->port.membase, up->reg_size); + of_iounmap(&op->resource[0], up->port.membase, up->reg_size); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 75de919a947..244f796dc62 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1379,13 +1379,15 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m if (!keyboard_mouse) { err = uart_add_one_port(&sunzilog_reg, &up[0].port); if (err) { - of_iounmap(rp, sizeof(struct zilog_layout)); + of_iounmap(&op->resource[0], + rp, sizeof(struct zilog_layout)); return err; } err = uart_add_one_port(&sunzilog_reg, &up[1].port); if (err) { uart_remove_one_port(&sunzilog_reg, &up[0].port); - of_iounmap(rp, sizeof(struct zilog_layout)); + of_iounmap(&op->resource[0], + rp, sizeof(struct zilog_layout)); return err; } } else { @@ -1414,18 +1416,18 @@ static void __devexit zs_remove_one(struct uart_sunzilog_port *up) uart_remove_one_port(&sunzilog_reg, &up->port); } -static int __devexit zs_remove(struct of_device *dev) +static int __devexit zs_remove(struct of_device *op) { - struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); + struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev); struct zilog_layout __iomem *regs; zs_remove_one(&up[0]); zs_remove_one(&up[1]); regs = sunzilog_chip_regs[up[0].port.line / 2]; - of_iounmap(regs, sizeof(struct zilog_layout)); + of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 92eba893559..db8607e3d53 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -278,8 +278,8 @@ static int ulite_request_port(struct uart_port *port) static void ulite_config_port(struct uart_port *port, int flags) { - ulite_request_port(port); - port->type = PORT_UARTLITE; + if (!ulite_request_port(port)) + port->type = PORT_UARTLITE; } static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 6ed3f1da929..8b41f9cc256 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1169,8 +1169,9 @@ static int setup(struct spi_device *spi) spi->bits_per_word - 16 : spi->bits_per_word) | SSCR0_SSE | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0); - chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4) - | (((spi->mode & SPI_CPOL) != 0) << 3); + chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH); + chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0) + | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); /* NOTE: PXA25x_SSP _could_ use external clocking ... */ if (drv_data->ssp_type != PXA25x_SSP) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 270e6211c2e..6307428d2c9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -366,7 +366,6 @@ spi_alloc_master(struct device *dev, unsigned size) class_device_initialize(&master->cdev); master->cdev.class = &spi_master_class; - kobj_set_kset_s(&master->cdev, spi_master_class.subsys); master->cdev.dev = get_device(dev); spi_master_set_devdata(master, &master[1]); @@ -466,14 +465,20 @@ EXPORT_SYMBOL_GPL(spi_unregister_master); */ struct spi_master *spi_busnum_to_master(u16 bus_num) { - char name[9]; - struct kobject *bus; - - snprintf(name, sizeof name, "spi%u", bus_num); - bus = kset_find_obj(&spi_master_class.subsys.kset, name); - if (bus) - return container_of(bus, struct spi_master, cdev.kobj); - return NULL; + struct class_device *cdev; + struct spi_master *master = NULL; + struct spi_master *m; + + down(&spi_master_class.sem); + list_for_each_entry(cdev, &spi_master_class.children, node) { + m = container_of(cdev, struct spi_master, cdev); + if (m->bus_num == bus_num) { + master = spi_master_get(m); + break; + } + } + up(&spi_master_class.sem); + return master; } EXPORT_SYMBOL_GPL(spi_busnum_to_master); diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index ff0b04895db..e9798bf7b8c 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c @@ -112,6 +112,8 @@ u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \ { \ u32 data; \ const type * tx = mpc83xx_spi->tx; \ + if (!tx) \ + return 0; \ data = *tx++; \ mpc83xx_spi->tx = tx; \ return data; \ diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 2ebe1fc4c39..651379c51ae 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -10,9 +10,6 @@ * */ - -//#define DEBUG - #include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -44,6 +41,9 @@ struct s3c24xx_spi { int len; int count; + int (*set_cs)(struct s3c2410_spi_info *spi, + int cs, int pol); + /* data buffers */ const unsigned char *tx; unsigned char *rx; @@ -64,6 +64,11 @@ static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) return spi_master_get_devdata(sdev->master); } +static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol) +{ + s3c2410_gpio_setpin(spi->pin_cs, pol); +} + static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) { struct s3c24xx_spi *hw = to_hw(spi); @@ -72,10 +77,7 @@ static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) switch (value) { case BITBANG_CS_INACTIVE: - if (hw->pdata->set_cs) - hw->pdata->set_cs(hw->pdata, value, cspol); - else - s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1); + hw->pdata->set_cs(hw->pdata, spi->chip_select, cspol^1); break; case BITBANG_CS_ACTIVE: @@ -96,14 +98,9 @@ static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) /* write new configration */ writeb(spcon, hw->regs + S3C2410_SPCON); - - if (hw->pdata->set_cs) - hw->pdata->set_cs(hw->pdata, value, cspol); - else - s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol); + hw->pdata->set_cs(hw->pdata, spi->chip_select, cspol); break; - } } @@ -174,7 +171,7 @@ static int s3c24xx_spi_setup(struct spi_device *spi) static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) { - return hw->tx ? hw->tx[count] : 0xff; + return hw->tx ? hw->tx[count] : 0; } static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) @@ -330,9 +327,12 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) /* setup any gpio we can */ if (!hw->pdata->set_cs) { + hw->set_cs = s3c24xx_spi_gpiocs; + s3c2410_gpio_setpin(hw->pdata->pin_cs, 1); s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT); - } + } else + hw->set_cs = hw->pdata->set_cs; /* register our spi controller */ diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c index a5d2cdfff46..eda53ed04cb 100644 --- a/drivers/spi/spi_s3c24xx_gpio.c +++ b/drivers/spi/spi_s3c24xx_gpio.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> +#include <linux/workqueue.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> @@ -22,7 +23,7 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/spi-gpio.h> -#include <asm/arch/hardware.h> +#include <asm/hardware.h> struct s3c2410_spigpio { struct spi_bitbang bitbang; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 6303970e93c..6377db1b446 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -130,7 +130,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H struct usblp { struct usb_device *dev; /* USB device */ - struct semaphore sem; /* locks this struct, especially "dev" */ + struct mutex mut; /* locks this struct, especially "dev" */ char *writebuf; /* write transfer_buffer */ char *readbuf; /* read transfer_buffer */ char *statusbuf; /* status transfer_buffer */ @@ -217,6 +217,7 @@ static const struct quirk_printer_struct quirk_printers[] = { { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ + { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */ { 0, 0 } }; @@ -465,7 +466,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int twoints[2]; int retval = 0; - down (&usblp->sem); + mutex_lock (&usblp->mut); if (!usblp->present) { retval = -ENODEV; goto done; @@ -644,14 +645,14 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } done: - up (&usblp->sem); + mutex_unlock (&usblp->mut); return retval; } static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - int timeout, rv, err = 0, transfer_length = 0; + int timeout, intr, rv, err = 0, transfer_length = 0; size_t writecount = 0; while (writecount < count) { @@ -668,14 +669,16 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if (rv < 0) return writecount ? writecount : -EINTR; } - down (&usblp->sem); + intr = mutex_lock_interruptible (&usblp->mut); + if (intr) + return writecount ? writecount : -EINTR; if (!usblp->present) { - up (&usblp->sem); + mutex_unlock (&usblp->mut); return -ENODEV; } if (usblp->sleeping) { - up (&usblp->sem); + mutex_unlock (&usblp->mut); return writecount ? writecount : -ENODEV; } @@ -687,10 +690,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t err = usblp->writeurb->status; } else err = usblp_check_status(usblp, err); - up (&usblp->sem); + mutex_unlock (&usblp->mut); /* if the fault was due to disconnect, let khubd's - * call to usblp_disconnect() grab usblp->sem ... + * call to usblp_disconnect() grab usblp->mut ... */ schedule (); continue; @@ -702,7 +705,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t */ writecount += transfer_length; if (writecount == count) { - up(&usblp->sem); + mutex_unlock(&usblp->mut); break; } @@ -714,7 +717,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) { - up(&usblp->sem); + mutex_unlock(&usblp->mut); return writecount ? writecount : -EFAULT; } @@ -727,10 +730,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count = -EIO; else count = writecount ? writecount : -ENOMEM; - up (&usblp->sem); + mutex_unlock (&usblp->mut); break; } - up (&usblp->sem); + mutex_unlock (&usblp->mut); } return count; @@ -739,12 +742,14 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - int rv; + int rv, intr; if (!usblp->bidir) return -EINVAL; - down (&usblp->sem); + intr = mutex_lock_interruptible (&usblp->mut); + if (intr) + return -EINTR; if (!usblp->present) { count = -ENODEV; goto done; @@ -757,9 +762,9 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, count = -EAGAIN; goto done; } - up(&usblp->sem); + mutex_unlock(&usblp->mut); rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present); - down(&usblp->sem); + mutex_lock(&usblp->mut); if (rv < 0) { count = -EINTR; goto done; @@ -807,7 +812,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, } done: - up (&usblp->sem); + mutex_unlock (&usblp->mut); return count; } @@ -886,7 +891,7 @@ static int usblp_probe(struct usb_interface *intf, goto abort; } usblp->dev = dev; - init_MUTEX (&usblp->sem); + mutex_init (&usblp->mut); init_waitqueue_head(&usblp->wait); usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; usblp->intf = intf; @@ -1178,7 +1183,7 @@ static void usblp_disconnect(struct usb_interface *intf) device_remove_file(&intf->dev, &dev_attr_ieee1284_id); mutex_lock (&usblp_mutex); - down (&usblp->sem); + mutex_lock (&usblp->mut); usblp->present = 0; usb_set_intfdata (intf, NULL); @@ -1187,7 +1192,7 @@ static void usblp_disconnect(struct usb_interface *intf) usblp->writebuf, usblp->writeurb->transfer_dma); usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, usblp->readbuf, usblp->readurb->transfer_dma); - up (&usblp->sem); + mutex_unlock (&usblp->mut); if (!usblp->used) usblp_cleanup (usblp); @@ -1200,11 +1205,11 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message) /* this races against normal access and open */ mutex_lock (&usblp_mutex); - down (&usblp->sem); + mutex_lock (&usblp->mut); /* we take no more IO */ usblp->sleeping = 1; usblp_unlink_urbs(usblp); - up (&usblp->sem); + mutex_unlock (&usblp->mut); mutex_unlock (&usblp_mutex); return 0; @@ -1216,12 +1221,12 @@ static int usblp_resume (struct usb_interface *intf) int r; mutex_lock (&usblp_mutex); - down (&usblp->sem); + mutex_lock (&usblp->mut); usblp->sleeping = 0; r = handle_bidir (usblp); - up (&usblp->sem); + mutex_unlock (&usblp->mut); mutex_unlock (&usblp_mutex); return r; diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index f8324d8d06a..3e66b2a9974 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -72,22 +72,6 @@ config USB_SUSPEND If you are unsure about this, say N here. -config USB_MULTITHREAD_PROBE - bool "USB Multi-threaded probe (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - default n - help - Say Y here if you want the USB core to spawn a new thread for - every USB device that is probed. This can cause a small speedup - in boot times on systems with a lot of different USB devices. - - This option should be safe to enable, but if any odd probing - problems are found, please disable it, or dynamically turn it - off in the /sys/module/usbcore/parameters/multithread_probe - file - - When in doubt, say N. - config USB_OTG bool depends on USB && EXPERIMENTAL diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3ed4cb2d56d..4b3a6ab29bd 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -962,7 +962,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EFAULT; } - snoop(&ps->dev->dev, "control urb\n"); + snoop(&ps->dev->dev, "control urb: bRequest=%02x " + "bRrequestType=%02x wValue=%04x " + "wIndex=%04x wLength=%04x\n", + dr->bRequest, dr->bRequestType, dr->wValue, + dr->wIndex, dr->wLength); break; case USBDEVFS_URB_TYPE_BULK: diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index c505b767cee..5e628ae3aec 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -268,6 +268,7 @@ static void ep_device_release(struct device *dev) struct ep_device *ep_dev = to_ep_device(dev); dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); + endpoint_free_minor(ep_dev); kfree(ep_dev); } @@ -349,7 +350,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint) sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); sysfs_remove_link(&ep_dev->dev.parent->kobj, name); sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); - endpoint_free_minor(ep_dev); device_unregister(&ep_dev->dev); endpoint->ep_dev = NULL; destroy_endpoint_class(); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2651c2e2a89..1988224b362 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -88,14 +88,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; /* multithreaded probe logic */ -static int multithread_probe = -#ifdef CONFIG_USB_MULTITHREAD_PROBE - 1; -#else - 0; -#endif -module_param(multithread_probe, bool, S_IRUGO); -MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread"); +static int multithread_probe = 0; /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 3e0abbb49fe..812c733ba8c 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -43,14 +43,16 @@ #include <linux/usb_gadget.h> #include <asm/byteorder.h> +#include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/system.h> #include <asm/mach-types.h> -#include <asm/arch/hardware.h> #include <asm/arch/gpio.h> #include <asm/arch/board.h> +#include <asm/arch/cpu.h> +#include <asm/arch/at91sam9261_matrix.h> #include "at91_udc.h" @@ -78,27 +80,11 @@ static const char driver_name [] = "at91_udc"; static const char ep0name[] = "ep0"; -/*-------------------------------------------------------------------------*/ -/* - * Read from a UDP register. - */ -static inline unsigned long at91_udp_read(unsigned int reg) -{ - void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP; - - return __raw_readl(udp_base + reg); -} - -/* - * Write to a UDP register. - */ -static inline void at91_udp_write(unsigned int reg, unsigned long value) -{ - void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP; - - __raw_writel(value, udp_base + reg); -} +#define at91_udp_read(dev, reg) \ + __raw_readl((dev)->udp_baseaddr + (reg)) +#define at91_udp_write(dev, reg, val) \ + __raw_writel((val), (dev)->udp_baseaddr + (reg)) /*-------------------------------------------------------------------------*/ @@ -210,13 +196,13 @@ static int proc_udc_show(struct seq_file *s, void *unused) return 0; } - tmp = at91_udp_read(AT91_UDP_FRM_NUM); + tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM); seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp, (tmp & AT91_UDP_FRM_OK) ? " ok" : "", (tmp & AT91_UDP_FRM_ERR) ? " err" : "", (tmp & AT91_UDP_NUM)); - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp, (tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "", (tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "", @@ -224,13 +210,13 @@ static int proc_udc_show(struct seq_file *s, void *unused) (tmp & AT91_UDP_CONFG) ? " confg" : "", (tmp & AT91_UDP_FADDEN) ? " fadden" : ""); - tmp = at91_udp_read(AT91_UDP_FADDR); + tmp = at91_udp_read(udc, AT91_UDP_FADDR); seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp, (tmp & AT91_UDP_FEN) ? " fen" : "", (tmp & AT91_UDP_FADD)); - proc_irq_show(s, "imr ", at91_udp_read(AT91_UDP_IMR)); - proc_irq_show(s, "isr ", at91_udp_read(AT91_UDP_ISR)); + proc_irq_show(s, "imr ", at91_udp_read(udc, AT91_UDP_IMR)); + proc_irq_show(s, "isr ", at91_udp_read(udc, AT91_UDP_ISR)); if (udc->enabled && udc->vbus) { proc_ep_show(s, &udc->ep[0]); @@ -286,6 +272,7 @@ static inline void remove_debug_file(struct at91_udc *udc) {} static void done(struct at91_ep *ep, struct at91_request *req, int status) { unsigned stopped = ep->stopped; + struct at91_udc *udc = ep->udc; list_del_init(&req->queue); if (req->req.status == -EINPROGRESS) @@ -301,7 +288,7 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status) /* ep0 is always ready; other endpoints need a non-empty queue */ if (list_empty(&ep->queue) && ep->int_mask != (1 << 0)) - at91_udp_write(AT91_UDP_IDR, ep->int_mask); + at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask); } /*-------------------------------------------------------------------------*/ @@ -554,8 +541,8 @@ ok: * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, * since endpoint resets don't reset hw pingpong state. */ - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(dev, AT91_UDP_RST_EP, 0); local_irq_restore(flags); return 0; @@ -564,6 +551,7 @@ ok: static int at91_ep_disable (struct usb_ep * _ep) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; unsigned long flags; if (ep == &ep->udc->ep[0]) @@ -579,8 +567,8 @@ static int at91_ep_disable (struct usb_ep * _ep) /* reset fifos and endpoint */ if (ep->udc->clocked) { - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); __raw_writel(0, ep->creg); } @@ -695,10 +683,10 @@ static int at91_ep_queue(struct usb_ep *_ep, * reconfigures the endpoints. */ if (dev->wait_for_config_ack) { - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT); tmp ^= AT91_UDP_CONFG; VDBG("toggle config\n"); - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp); } if (req->req.length == 0) { ep0_in_status: @@ -727,7 +715,7 @@ ep0_in_status: if (req && !status) { list_add_tail (&req->queue, &ep->queue); - at91_udp_write(AT91_UDP_IER, ep->int_mask); + at91_udp_write(dev, AT91_UDP_IER, ep->int_mask); } done: local_irq_restore(flags); @@ -758,6 +746,7 @@ static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) static int at91_ep_set_halt(struct usb_ep *_ep, int value) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; u32 __iomem *creg; u32 csr; unsigned long flags; @@ -785,8 +774,8 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) csr |= AT91_UDP_FORCESTALL; VDBG("halt %s\n", ep->ep.name); } else { - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); csr &= ~AT91_UDP_FORCESTALL; } __raw_writel(csr, creg); @@ -813,9 +802,11 @@ static struct usb_ep_ops at91_ep_ops = { static int at91_get_frame(struct usb_gadget *gadget) { + struct at91_udc *udc = to_udc(gadget); + if (!to_udc(gadget)->clocked) return -EINVAL; - return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM; + return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM; } static int at91_wakeup(struct usb_gadget *gadget) @@ -833,11 +824,11 @@ static int at91_wakeup(struct usb_gadget *gadget) /* NOTE: some "early versions" handle ESR differently ... */ - glbstate = at91_udp_read(AT91_UDP_GLB_STAT); + glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT); if (!(glbstate & AT91_UDP_ESR)) goto done; glbstate |= AT91_UDP_ESR; - at91_udp_write(AT91_UDP_GLB_STAT, glbstate); + at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); done: local_irq_restore(flags); @@ -861,6 +852,7 @@ static void udc_reinit(struct at91_udc *udc) ep->stopped = 0; ep->fifo_bank = 0; ep->ep.maxpacket = ep->maxpacket; + ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i); // initialiser une queue par endpoint INIT_LIST_HEAD(&ep->queue); } @@ -915,14 +907,41 @@ static void pullup(struct at91_udc *udc, int is_on) if (!udc->enabled || !udc->vbus) is_on = 0; DBG("%sactive\n", is_on ? "" : "in"); + if (is_on) { clk_on(udc); - at91_udp_write(AT91_UDP_TXVC, 0); - at91_set_gpio_value(udc->board.pullup_pin, 1); - } else { + at91_udp_write(udc, AT91_UDP_TXVC, 0); + if (cpu_is_at91rm9200()) + at91_set_gpio_value(udc->board.pullup_pin, 1); + else if (cpu_is_at91sam9260()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc |= AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261()) { + u32 usbpucr; + + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr |= AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } + } else { stop_activity(udc); - at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - at91_set_gpio_value(udc->board.pullup_pin, 0); + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + if (cpu_is_at91rm9200()) + at91_set_gpio_value(udc->board.pullup_pin, 0); + else if (cpu_is_at91sam9260()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc &= ~AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261()) { + u32 usbpucr; + + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr &= ~AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } clk_off(udc); } } @@ -936,7 +955,10 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active) // VDBG("vbus %s\n", is_active ? "on" : "off"); local_irq_save(flags); udc->vbus = (is_active != 0); - pullup(udc, is_active); + if (udc->driver) + pullup(udc, is_active); + else + pullup(udc, 0); local_irq_restore(flags); return 0; } @@ -1086,7 +1108,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) | USB_REQ_SET_CONFIGURATION: - tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; if (pkt.r.wValue) udc->wait_for_config_ack = (tmp == 0); else @@ -1103,7 +1125,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) | USB_REQ_GET_STATUS: tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED); - if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR) + if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR) tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP); PACKET("get device status\n"); __raw_writeb(tmp, dreg); @@ -1114,17 +1136,17 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_SET_FEATURE: if (w_value != USB_DEVICE_REMOTE_WAKEUP) goto stall; - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp |= AT91_UDP_ESR; - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); goto succeed; case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) | USB_REQ_CLEAR_FEATURE: if (w_value != USB_DEVICE_REMOTE_WAKEUP) goto stall; - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp &= ~AT91_UDP_ESR; - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); goto succeed; /* @@ -1206,8 +1228,8 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) } else if (ep->is_in) goto stall; - at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(AT91_UDP_RST_EP, 0); + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); tmp = __raw_readl(ep->creg); tmp |= CLR_FX; tmp &= ~(SET_FX | AT91_UDP_FORCESTALL); @@ -1222,7 +1244,10 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) #undef w_length /* pass request up to the gadget driver */ - status = udc->driver->setup(&udc->gadget, &pkt.r); + if (udc->driver) + status = udc->driver->setup(&udc->gadget, &pkt.r); + else + status = -ENODEV; if (status < 0) { stall: VDBG("req %02x.%02x protocol STALL; stat %d\n", @@ -1300,13 +1325,13 @@ static void handle_ep0(struct at91_udc *udc) if (udc->wait_for_addr_ack) { u32 tmp; - at91_udp_write(AT91_UDP_FADDR, + at91_udp_write(udc, AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr); - tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); tmp &= ~AT91_UDP_FADDEN; if (udc->addr) tmp |= AT91_UDP_FADDEN; - at91_udp_write(AT91_UDP_GLB_STAT, tmp); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); udc->wait_for_addr_ack = 0; VDBG("address %d\n", udc->addr); @@ -1374,28 +1399,28 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) while (rescans--) { u32 status; - status = at91_udp_read(AT91_UDP_ISR) - & at91_udp_read(AT91_UDP_IMR); + status = at91_udp_read(udc, AT91_UDP_ISR) + & at91_udp_read(udc, AT91_UDP_IMR); if (!status) break; /* USB reset irq: not maskable */ if (status & AT91_UDP_ENDBUSRES) { - at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); - at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS); + at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); + at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS); /* Atmel code clears this irq twice */ - at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES); - at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); VDBG("end bus reset\n"); udc->addr = 0; stop_activity(udc); /* enable ep0 */ - at91_udp_write(AT91_UDP_CSR(0), + at91_udp_write(udc, AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); udc->gadget.speed = USB_SPEED_FULL; udc->suspended = 0; - at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0)); + at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0)); /* * NOTE: this driver keeps clocks off unless the @@ -1406,9 +1431,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) /* host initiated suspend (3+ms bus idle) */ } else if (status & AT91_UDP_RXSUSP) { - at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP); - at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM); - at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP); // VDBG("bus suspend\n"); if (udc->suspended) continue; @@ -1425,9 +1450,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) /* host initiated resume */ } else if (status & AT91_UDP_RXRSM) { - at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM); - at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP); - at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); // VDBG("bus resume\n"); if (!udc->suspended) continue; @@ -1485,8 +1510,6 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(0)), .int_mask = 1 << 0, }, .ep[1] = { @@ -1497,8 +1520,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(1)), .int_mask = 1 << 1, }, .ep[2] = { @@ -1509,8 +1530,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(2)), .int_mask = 1 << 2, }, .ep[3] = { @@ -1521,8 +1540,6 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(3)), .int_mask = 1 << 3, }, .ep[4] = { @@ -1533,8 +1550,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(4)), .int_mask = 1 << 4, }, .ep[5] = { @@ -1545,8 +1560,6 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP - + AT91_UDP_CSR(5)), .int_mask = 1 << 5, }, /* ep6 and ep7 are also reserved (custom silicon might use them) */ @@ -1572,9 +1585,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) int retval; if (!driver - || driver->speed != USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->setup) { DBG("bad parameter.\n"); return -EINVAL; @@ -1595,6 +1607,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (retval) { DBG("driver->bind() returned %d\n", retval); udc->driver = NULL; + udc->gadget.dev.driver = NULL; + udc->gadget.dev.driver_data = NULL; + udc->enabled = 0; + udc->selfpowered = 0; return retval; } @@ -1611,12 +1627,12 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { struct at91_udc *udc = &controller; - if (!driver || driver != udc->driver) + if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; local_irq_disable(); udc->enabled = 0; - at91_udp_write(AT91_UDP_IDR, ~0); + at91_udp_write(udc, AT91_UDP_IDR, ~0); pullup(udc, 0); local_irq_enable(); @@ -1641,6 +1657,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct at91_udc *udc; int retval; + struct resource *res; if (!dev->platform_data) { /* small (so we copy it) but critical! */ @@ -1658,7 +1675,13 @@ static int __devinit at91udc_probe(struct platform_device *pdev) return -ENODEV; } - if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!request_mem_region(res->start, + res->end - res->start + 1, + driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; } @@ -1668,15 +1691,23 @@ static int __devinit at91udc_probe(struct platform_device *pdev) udc->gadget.dev.parent = dev; udc->board = *(struct at91_udc_data *) dev->platform_data; udc->pdev = pdev; - udc_reinit(udc); udc->enabled = 0; + udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1); + if (!udc->udp_baseaddr) { + release_mem_region(res->start, res->end - res->start + 1); + return -ENOMEM; + } + + udc_reinit(udc); + /* get interface and function clocks */ udc->iclk = clk_get(dev, "udc_clk"); udc->fclk = clk_get(dev, "udpck"); if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { DBG("clocks missing\n"); - return -ENODEV; + retval = -ENODEV; + goto fail0; } retval = device_register(&udc->gadget.dev); @@ -1685,8 +1716,10 @@ static int __devinit at91udc_probe(struct platform_device *pdev) /* don't do anything until we have both gadget driver and VBUS */ clk_enable(udc->iclk); - at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - at91_udp_write(AT91_UDP_IDR, 0xffffffff); + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); + /* Clear all pending interrupts - UDP may be used by bootloader. */ + at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ @@ -1698,6 +1731,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev) goto fail1; } if (udc->board.vbus_pin > 0) { + /* + * Get the initial state of VBUS - we cannot expect + * a pending interrupt. + */ + udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { DBG("request vbus irq %d failed\n", @@ -1720,7 +1758,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) fail1: device_unregister(&udc->gadget.dev); fail0: - release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); + release_mem_region(res->start, res->end - res->start + 1); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } @@ -1728,13 +1766,14 @@ fail0: static int __devexit at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); + struct resource *res; DBG("remove\n"); - pullup(udc, 0); + if (udc->driver) + return -EBUSY; - if (udc->driver != 0) - usb_gadget_unregister_driver(udc->driver); + pullup(udc, 0); device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); @@ -1742,7 +1781,10 @@ static int __devexit at91udc_remove(struct platform_device *pdev) free_irq(udc->board.vbus_pin, udc); free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); - release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); + + iounmap(udc->udp_baseaddr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); clk_put(udc->iclk); clk_put(udc->fclk); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 882af42e86c..677089baa59 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -51,10 +51,10 @@ #define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ #define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ #define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ -#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */ +#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ #define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ -#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */ +#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ #define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ @@ -84,7 +84,7 @@ #define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ #define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ - +#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */ /*-------------------------------------------------------------------------*/ @@ -141,6 +141,7 @@ struct at91_udc { struct clk *iclk, *fclk; struct platform_device *pdev; struct proc_dir_entry *pde; + void __iomem *udp_baseaddr; int udp_irq; }; diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f1f32d7be5f..3c2bc075ef4 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -779,7 +779,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) return -EINVAL; if (dum->driver) return -EBUSY; - if (!driver->bind || !driver->unbind || !driver->setup + if (!driver->bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; @@ -837,7 +837,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) err_bind_driver: driver_unregister (&driver->driver); err_register: - driver->unbind (&dum->gadget); + if (driver->unbind) + driver->unbind (&dum->gadget); spin_lock_irq (&dum->lock); dum->pullup = 0; set_link_state (dum); @@ -857,7 +858,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!dum) return -ENODEV; - if (!driver || driver != dum->driver) + if (!driver || driver != dum->driver || !driver->unbind) return -EINVAL; dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a265e262a2e..72f2ae96fbf 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -4100,7 +4100,7 @@ static struct usb_gadget_driver fsg_driver = { #endif .function = (char *) longname, .bind = fsg_bind, - .unbind = __exit_p(fsg_unbind), + .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, .suspend = fsg_suspend, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 31351826f2b..f1a679656c9 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -123,7 +123,7 @@ struct gmidi_device { struct usb_request *req; /* for control responses */ u8 config; struct usb_ep *in_ep, *out_ep; - struct snd_card *card; + struct snd_card *card; struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *in_substream; struct snd_rawmidi_substream *out_substream; @@ -490,7 +490,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req) int status = req->status; switch (status) { - case 0: /* normal completion */ + case 0: /* normal completion */ if (ep == dev->out_ep) { /* we received stuff. req is queued again, below */ @@ -505,7 +505,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req) break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + 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, @@ -656,7 +656,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -1308,7 +1308,7 @@ static struct usb_gadget_driver gmidi_driver = { .speed = USB_SPEED_FULL, .function = (char *)longname, .bind = gmidi_bind, - .unbind = __exit_p(gmidi_unbind), + .unbind = gmidi_unbind, .setup = gmidi_setup, .disconnect = gmidi_disconnect, @@ -1316,7 +1316,7 @@ static struct usb_gadget_driver gmidi_driver = { .suspend = gmidi_suspend, .resume = gmidi_resume, - .driver = { + .driver = { .name = (char *)shortname, .owner = THIS_MODULE, }, diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 805a9826842..d0ef1d6b3fa 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1432,7 +1432,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1495,7 +1494,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); @@ -1808,13 +1807,8 @@ static void goku_remove(struct pci_dev *pdev) struct goku_udc *dev = pci_get_drvdata(pdev); DBG(dev, "%s\n", __FUNCTION__); - /* start with the driver above us */ - if (dev->driver) { - /* should have been done already by driver model core */ - WARN(dev, "pci remove, driver '%s' is still registered\n", - dev->driver->driver.name); - usb_gadget_unregister_driver(dev->driver); - } + + BUG_ON(dev->driver); #ifdef CONFIG_USB_GADGET_DEBUG_FILES remove_proc_entry(proc_node_name, NULL); diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 4a991564a03..a0a73c08a34 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -422,9 +422,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name); if (!driver - || driver->speed != USB_SPEED_FULL - || !driver->bind - || !driver->unbind || !driver->disconnect || !driver->setup) + || driver->speed != USB_SPEED_FULL + || !driver->bind + || !driver->disconnect + || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; @@ -471,7 +472,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); @@ -2125,9 +2126,11 @@ static int lh7a40x_udc_remove(struct platform_device *pdev) DEBUG("%s: %p\n", __FUNCTION__, pdev); + if (dev->driver) + return -EBUSY; + udc_disable(dev); remove_proc_files(); - usb_gadget_unregister_driver(dev->driver); free_irq(IRQ_USBINTR, dev); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 3024c679e38..569eb8ccf23 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2020,7 +2020,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_HIGH || !driver->bind - || !driver->unbind || !driver->setup) return -EINVAL; if (!dev) @@ -2107,7 +2106,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave (&dev->lock, flags); @@ -2803,13 +2802,7 @@ static void net2280_remove (struct pci_dev *pdev) { struct net2280 *dev = pci_get_drvdata (pdev); - /* start with the driver above us */ - if (dev->driver) { - /* should have been done already by driver model core */ - WARN (dev, "pci remove, driver '%s' is still registered\n", - dev->driver->driver.name); - usb_gadget_unregister_driver (dev->driver); - } + BUG_ON(dev->driver); /* then clean up the resources we allocated during probe() */ net2280_led_shutdown (dev); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 030d87c28c2..cdcfd42843d 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -42,6 +42,7 @@ #include <linux/usb_gadget.h> #include <linux/usb/otg.h> #include <linux/dma-mapping.h> +#include <linux/clk.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -60,6 +61,11 @@ /* bulk DMA seems to be behaving for both IN and OUT */ #define USE_DMA +/* FIXME: OMAP2 currently has some problem in DMA mode */ +#ifdef CONFIG_ARCH_OMAP2 +#undef USE_DMA +#endif + /* ISO too */ #define USE_ISO @@ -99,7 +105,7 @@ static unsigned fifo_mode = 0; * boot parameter "omap_udc:fifo_mode=42" */ module_param (fifo_mode, uint, 0); -MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)"); +MODULE_PARM_DESC (fifo_mode, "endpoint configuration"); #ifdef USE_DMA static unsigned use_dma = 1; @@ -122,7 +128,7 @@ static const char driver_desc [] = DRIVER_DESC; /*-------------------------------------------------------------------------*/ /* there's a notion of "current endpoint" for modifying endpoint - * state, and PIO access to its FIFO. + * state, and PIO access to its FIFO. */ static void use_ep(struct omap_ep *ep, u16 select) @@ -391,7 +397,7 @@ done(struct omap_ep *ep, struct omap_req *req, int status) #define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) -static inline int +static inline int write_packet(u8 *buf, struct omap_req *req, unsigned max) { unsigned len; @@ -456,7 +462,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req) return is_last; } -static inline int +static inline int read_packet(u8 *buf, struct omap_req *req, unsigned avail) { unsigned len; @@ -542,9 +548,9 @@ static inline dma_addr_t dma_csac(unsigned lch) /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is * read before the DMA controller finished disabling the channel. */ - csac = omap_readw(OMAP_DMA_CSAC(lch)); + csac = OMAP_DMA_CSAC_REG(lch); if (csac == 0) - csac = omap_readw(OMAP_DMA_CSAC(lch)); + csac = OMAP_DMA_CSAC_REG(lch); return csac; } @@ -555,9 +561,9 @@ static inline dma_addr_t dma_cdac(unsigned lch) /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is * read before the DMA controller finished disabling the channel. */ - cdac = omap_readw(OMAP_DMA_CDAC(lch)); + cdac = OMAP_DMA_CDAC_REG(lch); if (cdac == 0) - cdac = omap_readw(OMAP_DMA_CDAC(lch)); + cdac = OMAP_DMA_CDAC_REG(lch); return cdac; } @@ -582,7 +588,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) } #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \ - ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \ + ? OMAP_DMA_CSAC_REG(x) /* really: CPC */ \ : dma_cdac(x)) static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start) @@ -620,17 +626,19 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - length, 1, sync_mode); + length, 1, sync_mode, 0, 0); } else { length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); - txdma_ctrl = length; + txdma_ctrl = length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, - ep->ep.maxpacket >> 1, length, sync_mode); + ep->ep.maxpacket >> 1, length, sync_mode, + 0, 0); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, - OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, + 0, 0); omap_start_dma(ep->lch); ep->dma_counter = dma_csac(ep->lch); @@ -675,9 +683,11 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) req->dma_bytes = packets * ep->ep.maxpacket; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, ep->ep.maxpacket >> 1, packets, - OMAP_DMA_SYNC_ELEMENT); + OMAP_DMA_SYNC_ELEMENT, + 0, 0); omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, - OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); + OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, + 0, 0); ep->dma_counter = DMA_DEST_LAST(ep->lch); UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); @@ -820,7 +830,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, - (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), + 0, 0); } } else { status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel, @@ -831,7 +842,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, - (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG), + 0, 0); /* EMIFF */ omap_set_dma_dest_burst_mode(ep->lch, OMAP_DMA_DATA_BURST_4); @@ -846,7 +858,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) /* channel type P: hw synch (fifo) */ if (!cpu_is_omap15xx()) - omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch)); + OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2; } just_restart: @@ -893,7 +905,7 @@ static void dma_channel_release(struct omap_ep *ep) else req = NULL; - active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; + active = ((1 << 7) & OMAP_DMA_CCR_REG(ep->lch)) != 0; DBG("%s release %s %cxdma%d %p\n", ep->ep.name, active ? "active" : "idle", @@ -1117,7 +1129,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) */ dma_channel_release(ep); dma_channel_claim(ep, channel); - } else + } else done(ep, req, -ECONNRESET); spin_unlock_irqrestore(&ep->udc->lock, flags); return 0; @@ -1153,7 +1165,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) /* IN endpoints must already be idle */ if ((ep->bEndpointAddress & USB_DIR_IN) - && !list_empty(&ep->queue)) { + && !list_empty(&ep->queue)) { status = -EAGAIN; goto done; } @@ -1298,6 +1310,23 @@ static void pullup_disable(struct omap_udc *udc) UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } +static struct omap_udc *udc; + +static void omap_udc_enable_clock(int enable) +{ + if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL) + return; + + if (enable) { + clk_enable(udc->dc_clk); + clk_enable(udc->hhc_clk); + udelay(100); + } else { + clk_disable(udc->hhc_clk); + clk_disable(udc->dc_clk); + } +} + /* * Called by whatever detects VBUS sessions: external transceiver * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. @@ -1318,10 +1347,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active) else FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510; } + if (udc->dc_clk != NULL && is_active) { + if (!udc->clk_requested) { + omap_udc_enable_clock(1); + udc->clk_requested = 1; + } + } if (can_pullup(udc)) pullup_enable(udc); else pullup_disable(udc); + if (udc->dc_clk != NULL && !is_active) { + if (udc->clk_requested) { + omap_udc_enable_clock(0); + udc->clk_requested = 0; + } + } spin_unlock_irqrestore(&udc->lock, flags); return 0; } @@ -1441,7 +1482,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) } } - /* IN/OUT packets mean we're in the DATA or STATUS stage. + /* IN/OUT packets mean we're in the DATA or STATUS stage. * This driver uses only uses protocol stalls (ep0 never halts), * and if we got this far the gadget driver already had a * chance to stall. Tries to be forgiving of host oddities. @@ -1509,7 +1550,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) } else if (stat == 0) UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = 0; - + /* activate status stage */ if (stat == 1) { done(ep0, req, 0); @@ -1866,7 +1907,7 @@ static void pio_out_timer(unsigned long _ep) spin_lock_irqsave(&ep->udc->lock, flags); if (!list_empty(&ep->queue) && ep->ackwait) { - use_ep(ep, 0); + use_ep(ep, UDC_EP_SEL); stat_flg = UDC_STAT_FLG_REG; if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN) @@ -1876,12 +1917,12 @@ static void pio_out_timer(unsigned long _ep) VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg); req = container_of(ep->queue.next, struct omap_req, queue); - UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL; (void) read_fifo(ep, req); UDC_EP_NUM_REG = ep->bEndpointAddress; UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; - } + } else + deselect_ep(); } mod_timer(&ep->timer, PIO_OUT_TIMEOUT); spin_unlock_irqrestore(&ep->udc->lock, flags); @@ -2028,7 +2069,17 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) /*-------------------------------------------------------------------------*/ -static struct omap_udc *udc; +static inline int machine_needs_vbus_session(void) +{ + return (machine_is_omap_innovator() + || machine_is_omap_osk() + || machine_is_omap_apollon() +#ifndef CONFIG_MACH_OMAP_H4_OTG + || machine_is_omap_h4() +#endif + || machine_is_sx1() + ); +} int usb_gadget_register_driver (struct usb_gadget_driver *driver) { @@ -2043,7 +2094,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) // FIXME if otg, check: driver->is_otg || driver->speed < USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->setup) return -EINVAL; @@ -2071,6 +2121,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); + if (udc->dc_clk != NULL) + omap_udc_enable_clock(1); + status = driver->bind (&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); @@ -2087,9 +2140,11 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) status = otg_set_peripheral(udc->transceiver, &udc->gadget); if (status < 0) { ERR("can't bind to transceiver\n"); - driver->unbind (&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; + if (driver->unbind) { + driver->unbind (&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + } goto done; } } else { @@ -2102,10 +2157,12 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) /* boards that don't have VBUS sensing can't autogate 48MHz; * can't enter deep sleep while a gadget driver is active. */ - if (machine_is_omap_innovator() || machine_is_omap_osk()) + if (machine_needs_vbus_session()) omap_vbus_session(&udc->gadget, 1); done: + if (udc->dc_clk != NULL) + omap_udc_enable_clock(0); return status; } EXPORT_SYMBOL(usb_gadget_register_driver); @@ -2117,10 +2174,13 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!udc) return -ENODEV; - if (!driver || driver != udc->driver) + if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; - if (machine_is_omap_innovator() || machine_is_omap_osk()) + if (udc->dc_clk != NULL) + omap_udc_enable_clock(1); + + if (machine_needs_vbus_session()) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) @@ -2136,6 +2196,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) udc->gadget.dev.driver = NULL; udc->driver = NULL; + if (udc->dc_clk != NULL) + omap_udc_enable_clock(0); DBG("unregistered driver '%s'\n", driver->driver.name); return status; } @@ -2218,7 +2280,7 @@ static char *trx_mode(unsigned m, int enabled) case 0: return enabled ? "*6wire" : "unused"; case 1: return "4wire"; case 2: return "3wire"; - case 3: return "6wire"; + case 3: return "6wire"; default: return "unknown"; } } @@ -2227,11 +2289,18 @@ static int proc_otg_show(struct seq_file *s) { u32 tmp; u32 trans; + char *ctrl_name; tmp = OTG_REV_REG; - trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n", - tmp >> 4, tmp & 0xf, trans); + if (cpu_is_omap24xx()) { + ctrl_name = "control_devconf"; + trans = CONTROL_DEVCONF_REG; + } else { + ctrl_name = "tranceiver_ctrl"; + trans = USB_TRANSCEIVER_CTRL_REG; + } + seq_printf(s, "\nOTG rev %d.%d, %s %05x\n", + tmp >> 4, tmp & 0xf, ctrl_name, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, @@ -2306,7 +2375,7 @@ static int proc_udc_show(struct seq_file *s, void *_) driver_desc, use_dma ? " (dma)" : ""); - tmp = UDC_REV_REG & 0xff; + tmp = UDC_REV_REG & 0xff; seq_printf(s, "UDC rev %d.%d, fifo mode %d, gadget %s\n" "hmc %d, transceiver %s\n", @@ -2314,11 +2383,16 @@ static int proc_udc_show(struct seq_file *s, void *_) fifo_mode, udc->driver ? udc->driver->driver.name : "(none)", HMC, - udc->transceiver ? udc->transceiver->label : "(none)"); - seq_printf(s, "ULPD control %04x req %04x status %04x\n", - __REG16(ULPD_CLOCK_CTRL), - __REG16(ULPD_SOFT_REQ), - __REG16(ULPD_STATUS_REQ)); + udc->transceiver + ? udc->transceiver->label + : ((cpu_is_omap1710() || cpu_is_omap24xx()) + ? "external" : "(none)")); + if (cpu_class_is_omap1()) { + seq_printf(s, "ULPD control %04x req %04x status %04x\n", + __REG16(ULPD_CLOCK_CTRL), + __REG16(ULPD_SOFT_REQ), + __REG16(ULPD_STATUS_REQ)); + } /* OTG controller registers */ if (!cpu_is_omap15xx()) @@ -2503,9 +2577,10 @@ omap_ep_setup(char *name, u8 addr, u8 type, dbuf = 1; } else { /* double-buffering "not supported" on 15xx, - * and ignored for PIO-IN on 16xx + * and ignored for PIO-IN on newer chips + * (for more reliable behavior) */ - if (!use_dma || cpu_is_omap15xx()) + if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx()) dbuf = 0; switch (maxp) { @@ -2548,7 +2623,7 @@ omap_ep_setup(char *name, u8 addr, u8 type, ep->bEndpointAddress = addr; ep->bmAttributes = type; ep->double_buf = dbuf; - ep->udc = udc; + ep->udc = udc; ep->ep.name = ep->name; ep->ep.ops = &omap_ep_ops; @@ -2708,15 +2783,37 @@ static int __init omap_udc_probe(struct platform_device *pdev) struct otg_transceiver *xceiv = NULL; const char *type = NULL; struct omap_usb_config *config = pdev->dev.platform_data; + struct clk *dc_clk; + struct clk *hhc_clk; /* NOTE: "knows" the order of the resources! */ - if (!request_mem_region(pdev->resource[0].start, + if (!request_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1, driver_name)) { DBG("request_mem_region failed\n"); return -EBUSY; } + if (cpu_is_omap16xx()) { + dc_clk = clk_get(&pdev->dev, "usb_dc_ck"); + hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck"); + BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); + /* can't use omap_udc_enable_clock yet */ + clk_enable(dc_clk); + clk_enable(hhc_clk); + udelay(100); + } + + if (cpu_is_omap24xx()) { + dc_clk = clk_get(&pdev->dev, "usb_fck"); + hhc_clk = clk_get(&pdev->dev, "usb_l4_ick"); + BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); + /* can't use omap_udc_enable_clock yet */ + clk_enable(dc_clk); + clk_enable(hhc_clk); + udelay(100); + } + INFO("OMAP UDC rev %d.%d%s\n", UDC_REV_REG >> 4, UDC_REV_REG & 0xf, config->otg ? ", Mini-AB" : ""); @@ -2726,7 +2823,7 @@ static int __init omap_udc_probe(struct platform_device *pdev) hmc = HMC_1510; type = "(unknown)"; - if (machine_is_omap_innovator()) { + if (machine_is_omap_innovator() || machine_is_sx1()) { /* just set up software VBUS detect, and then * later rig it so we always report VBUS. * FIXME without really sensing VBUS, we can't @@ -2755,6 +2852,15 @@ static int __init omap_udc_probe(struct platform_device *pdev) } hmc = HMC_1610; + + if (cpu_is_omap24xx()) { + /* this could be transceiverless in one of the + * "we don't need to know" modes. + */ + type = "external"; + goto known; + } + switch (hmc) { case 0: /* POWERUP DEFAULT == 0 */ case 4: @@ -2793,6 +2899,7 @@ bad_on_1710: goto cleanup0; } } +known: INFO("hmc mode %d, %s transceiver\n", hmc, type); /* a "gadget" abstracts/virtualizes the controller */ @@ -2817,8 +2924,8 @@ bad_on_1710: status = request_irq(pdev->resource[1].start, omap_udc_irq, IRQF_SAMPLE_RANDOM, driver_name, udc); if (status != 0) { - ERR( "can't get irq %ld, err %d\n", - pdev->resource[1].start, status); + ERR("can't get irq %d, err %d\n", + (int) pdev->resource[1].start, status); goto cleanup1; } @@ -2826,24 +2933,41 @@ bad_on_1710: status = request_irq(pdev->resource[2].start, omap_udc_pio_irq, IRQF_SAMPLE_RANDOM, "omap_udc pio", udc); if (status != 0) { - ERR( "can't get irq %ld, err %d\n", - pdev->resource[2].start, status); + ERR("can't get irq %d, err %d\n", + (int) pdev->resource[2].start, status); goto cleanup2; } #ifdef USE_ISO status = request_irq(pdev->resource[3].start, omap_udc_iso_irq, IRQF_DISABLED, "omap_udc iso", udc); if (status != 0) { - ERR("can't get irq %ld, err %d\n", - pdev->resource[3].start, status); + ERR("can't get irq %d, err %d\n", + (int) pdev->resource[3].start, status); goto cleanup3; } #endif + if (cpu_is_omap16xx()) { + udc->dc_clk = dc_clk; + udc->hhc_clk = hhc_clk; + clk_disable(hhc_clk); + clk_disable(dc_clk); + } + + if (cpu_is_omap24xx()) { + udc->dc_clk = dc_clk; + udc->hhc_clk = hhc_clk; + /* FIXME OMAP2 don't release hhc & dc clock */ +#if 0 + clk_disable(hhc_clk); + clk_disable(dc_clk); +#endif + } create_proc_file(); - device_add(&udc->gadget.dev); - return 0; - + status = device_add(&udc->gadget.dev); + if (!status) + return status; + /* If fail, fall through */ #ifdef USE_ISO cleanup3: free_irq(pdev->resource[2].start, udc); @@ -2859,8 +2983,17 @@ cleanup1: cleanup0: if (xceiv) put_device(xceiv->dev); + + if (cpu_is_omap16xx() || cpu_is_omap24xx()) { + clk_disable(hhc_clk); + clk_disable(dc_clk); + clk_put(hhc_clk); + clk_put(dc_clk); + } + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); + return status; } @@ -2870,6 +3003,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev) if (!udc) return -ENODEV; + if (udc->driver) + return -EBUSY; udc->done = &done; @@ -2888,6 +3023,13 @@ static int __exit omap_udc_remove(struct platform_device *pdev) free_irq(pdev->resource[2].start, udc); free_irq(pdev->resource[1].start, udc); + if (udc->dc_clk) { + if (udc->clk_requested) + omap_udc_enable_clock(0); + clk_put(udc->hhc_clk); + clk_put(udc->dc_clk); + } + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index 652ee462734..1dc398bb9ab 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -175,6 +175,9 @@ struct omap_udc { unsigned ep0_reset_config:1; unsigned ep0_setup:1; struct completion *done; + struct clk *dc_clk; + struct clk *hhc_clk; + unsigned clk_requested:1; }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1ed506e9598..b78de969466 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1623,7 +1623,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind - || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1694,7 +1693,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!dev) return -ENODEV; - if (!driver || driver != dev->driver) + if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; local_irq_disable(); @@ -2638,9 +2637,11 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) { struct pxa2xx_udc *dev = platform_get_drvdata(pdev); + if (dev->driver) + return -EBUSY; + udc_disable(dev); remove_proc_files(); - usb_gadget_unregister_driver(dev->driver); if (dev->got_irq) { free_irq(IRQ_USB, dev); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 2d12bf9f19d..f8a3ec64635 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -296,7 +296,7 @@ static struct usb_gadget_driver gs_gadget_driver = { #endif /* CONFIG_USB_GADGET_DUALSPEED */ .function = GS_LONG_NAME, .bind = gs_bind, - .unbind = __exit_p(gs_unbind), + .unbind = gs_unbind, .setup = gs_setup, .disconnect = gs_disconnect, .driver = { diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index b466581beb4..cc405512fa1 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -187,7 +187,6 @@ ohci_at91_start (struct usb_hcd *hcd) { struct at91_usbh_data *board = hcd->self.controller->platform_data; struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct usb_device *root = hcd->self.root_hub; int ret; if ((ret = ohci_init(ohci)) < 0) @@ -221,7 +220,7 @@ static const struct hc_driver ohci_at91_hc_driver = { */ .start = ohci_at91_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 24e23c5783d..e70b2430e2a 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -269,7 +269,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .start = ohci_au1xxx_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -336,7 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_au1xxx_driver = { .probe = ohci_hcd_au1xxx_drv_probe, .remove = ohci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_au1xxx_drv_suspend, */ /*.resume = ohci_hcd_au1xxx_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 0f47a57dac2..273d5ddb72b 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -16,7 +16,7 @@ case PIPE_CONTROL: temp = "ctrl"; break; \ case PIPE_BULK: temp = "bulk"; break; \ case PIPE_INTERRUPT: temp = "intr"; break; \ - default: temp = "isoc"; break; \ + default: temp = "isoc"; break; \ }; temp;}) #define pipestring(pipe) edstring(usb_pipetype(pipe)) @@ -205,13 +205,13 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) (temp & RH_PS_PSSC) ? " PSSC" : "", \ (temp & RH_PS_PESC) ? " PESC" : "", \ (temp & RH_PS_CSC) ? " CSC" : "", \ - \ + \ (temp & RH_PS_LSDA) ? " LSDA" : "", \ (temp & RH_PS_PPS) ? " PPS" : "", \ (temp & RH_PS_PRS) ? " PRS" : "", \ (temp & RH_PS_POCI) ? " POCI" : "", \ (temp & RH_PS_PSS) ? " PSS" : "", \ - \ + \ (temp & RH_PS_PES) ? " PES" : "", \ (temp & RH_PS_CCS) ? " CCS" : "" \ ); @@ -563,7 +563,7 @@ show_periodic (struct class_device *class_dev, char *buf) (info & ED_SKIP) ? " K" : "", (ed->hwHeadP & cpu_to_hc32(ohci, ED_H)) ? - " H" : ""); + " H" : ""); size -= temp; next += temp; diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 1bf5e7a4e73..3348b07f0fe 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -169,7 +169,7 @@ static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ochi_hcd *ohci = hcd_to_ohci(hcd); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); @@ -204,7 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) static struct platform_driver ohci_hcd_ep93xx_driver = { .probe = ohci_hcd_ep93xx_drv_probe, .remove = ohci_hcd_ep93xx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_hcd_ep93xx_drv_suspend, .resume = ohci_hcd_ep93xx_drv_resume, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index b28a9b60206..c1c1d871aba 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -3,77 +3,21 @@ * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net> - * + * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] * [ (C) Copyright 1999 Linus Torvalds ] * [ (C) Copyright 1999 Gregory P. Smith] - * - * + * + * * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller * interfaces (though some non-x86 Intel chips use it). It supports * smarter hardware than UHCI. A download link for the spec available * through the http://www.usb.org website. * - * History: - * - * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer) - * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net) - * 2003/02/24 show registers in sysfs (Kevin Brosius) - * - * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and - * bandwidth accounting; if debugging, show schedules in driverfs - * 2002/07/19 fixes to management of ED and schedule state. - * 2002/06/09 SA-1111 support (Christopher Hoover) - * 2002/06/01 remember frame when HC won't see EDs any more; use that info - * to fix urb unlink races caused by interrupt latency assumptions; - * minor ED field and function naming updates - * 2002/01/18 package as a patch for 2.5.3; this should match the - * 2.4.17 kernel modulo some bugs being fixed. - * - * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes - * from post-2.4.5 patches. - * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning - * 2001/09/07 match PCI PM changes, errnos from Linus' tree - * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify; - * pbook pci quirks gone (please fix pbook pci sw!) (db) - * - * 2001/04/08 Identify version on module load (gb) - * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam); - pci_map_single (db) - * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db) - * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam) - * - * 2000/09/26 fixed races in removing the private portion of the urb - * 2000/09/07 disable bulk and control lists when unlinking the last - * endpoint descriptor in order to avoid unrecoverable errors on - * the Lucent chips. (rwc@sgi) - * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some - * urb unlink probs, indentation fixes - * 2000/08/11 various oops fixes mostly affecting iso and cleanup from - * device unplugs. - * 2000/06/28 use PCI hotplug framework, for better power management - * and for Cardbus support (David Brownell) - * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling - * when the controller loses power; handle UE; cleanup; ... - * - * v5.2 1999/12/07 URB 3rd preview, - * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi) - * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume - * i386: HUB, Keyboard, Mouse, Printer - * - * v4.3 1999/10/27 multiple HCs, bulk_request - * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes - * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl. - * v4.0 1999/08/18 - * v3.0 1999/06/25 - * v2.1 1999/05/09 code clean up - * v2.0 1999/05/04 - * v1.0 1999/04/27 initial release - * * This file is licenced under the GPL. */ - + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/pci.h> @@ -89,7 +33,7 @@ #include <linux/list.h> #include <linux/usb.h> #include <linux/usb/otg.h> -#include <linux/dma-mapping.h> +#include <linux/dma-mapping.h> #include <linux/dmapool.h> #include <linux/reboot.h> @@ -183,11 +127,11 @@ static int ohci_urb_enqueue ( int i, size = 0; unsigned long flags; int retval = 0; - + #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "SUB", usb_pipein (pipe)); #endif - + /* every endpoint has a ed, locate and maybe (re)initialize it */ if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) return -ENOMEM; @@ -232,7 +176,7 @@ static int ohci_urb_enqueue ( memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); INIT_LIST_HEAD (&urb_priv->pending); urb_priv->length = size; - urb_priv->ed = ed; + urb_priv->ed = ed; /* allocate the TDs (deferring hash chain updates) */ for (i = 0; i < size; i++) { @@ -242,7 +186,7 @@ static int ohci_urb_enqueue ( urb_free_priv (ohci, urb_priv); return -ENOMEM; } - } + } spin_lock_irqsave (&ohci->lock, flags); @@ -313,13 +257,13 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; - + #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "UNLINK", 1); -#endif +#endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -512,11 +456,11 @@ static int ohci_init (struct ohci_hcd *ohci) /* Start an OHCI controller, set the BUS operational * resets USB and controller - * enable interrupts + * enable interrupts */ static int ohci_run (struct ohci_hcd *ohci) { - u32 mask, temp; + u32 mask, temp; int first = ohci->fminterval == 0; struct usb_hcd *hcd = ohci_to_hcd(ohci); @@ -534,7 +478,7 @@ static int ohci_run (struct ohci_hcd *ohci) /* also: power/overcurrent flags in roothub.a */ } - /* Reset USB nearly "by the book". RemoteWakeupConnected was + /* Reset USB nearly "by the book". RemoteWakeupConnected was * saved if boot firmware (BIOS/SMM/...) told us it's connected, * or if bus glue did the same (e.g. for PCI add-in cards with * PCI PM support). @@ -765,9 +709,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) dl_done_list (ohci); spin_unlock (&ohci->lock); if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } - + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -778,12 +722,12 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) finish_unlinks (ohci, ohci_frame_no(ohci)); if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); + ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); if (HC_IS_RUNNING(hcd->state)) { ohci_writel (ohci, ints, ®s->intrstatus); - ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); + ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); } @@ -794,7 +738,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ static void ohci_stop (struct usb_hcd *hcd) -{ +{ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n", @@ -812,8 +756,8 @@ static void ohci_stop (struct usb_hcd *hcd) remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { - dma_free_coherent (hcd->self.controller, - sizeof *ohci->hcca, + dma_free_coherent (hcd->self.controller, + sizeof *ohci->hcca, ohci->hcca, ohci->hcca_dma); ohci->hcca = NULL; ohci->hcca_dma = 0; @@ -836,7 +780,7 @@ static int ohci_restart (struct ohci_hcd *ohci) * recycle any "live" eds/tds (and urbs) right away. * later, khubd disconnect processing will recycle the other state, * (either as disconnect/reconnect, or maybe someday as a reset). - */ + */ spin_lock_irq(&ohci->lock); disable (ohci); usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub); @@ -875,11 +819,11 @@ static int ohci_restart (struct ohci_hcd *ohci) /* empty the interrupt branches */ for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0; - + /* no EDs to remove */ ohci->ed_rm_list = NULL; - /* empty control and bulk lists */ + /* empty control and bulk lists */ ohci->ed_controltail = NULL; ohci->ed_bulktail = NULL; @@ -941,6 +885,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-au1xxx.c" #endif +#ifdef CONFIG_PNX8550 +#include "ohci-pnx8550.c" +#endif + #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC #include "ohci-ppc-soc.c" #endif diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 2441642cb7b..216c9c9d4d6 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net> - * + * * This file is licenced under GPL */ @@ -23,13 +23,13 @@ (temp & RH_PS_PSSC) ? " PSSC" : "", \ (temp & RH_PS_PESC) ? " PESC" : "", \ (temp & RH_PS_CSC) ? " CSC" : "", \ - \ + \ (temp & RH_PS_LSDA) ? " LSDA" : "", \ (temp & RH_PS_PPS) ? " PPS" : "", \ (temp & RH_PS_PRS) ? " PRS" : "", \ (temp & RH_PS_POCI) ? " POCI" : "", \ (temp & RH_PS_PSS) ? " PSS" : "", \ - \ + \ (temp & RH_PS_PES) ? " PES" : "", \ (temp & RH_PS_CCS) ? " CCS" : "" \ ); @@ -484,7 +484,7 @@ ohci_hub_descriptor ( temp = 0; if (rh & RH_A_NPS) /* no power switching? */ temp |= 0x0002; - if (rh & RH_A_PSM) /* per-port power switching? */ + if (rh & RH_A_PSM) /* per-port power switching? */ temp |= 0x0001; if (rh & RH_A_NOCP) /* no overcurrent reporting? */ temp |= 0x0010; @@ -555,7 +555,7 @@ static void start_hnp(struct ohci_hcd *ohci); #define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) /* called from some task, normally khubd */ -static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) +static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) { __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; u32 temp; @@ -570,10 +570,13 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) /* spin until any current reset finishes */ for (;;) { temp = ohci_readl (ohci, portstat); + /* handle e.g. CardBus eject */ + if (temp == ~(u32)0) + return -ESHUTDOWN; if (!(temp & RH_PS_PRS)) break; udelay (500); - } + } if (!(temp & RH_PS_CCS)) break; @@ -586,6 +589,8 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) now = ohci_readl(ohci, &ohci->regs->fmnumber); } while (tick_before(now, reset_done)); /* caller synchronizes using PRSC */ + + return 0; } static int ohci_hub_control ( @@ -702,7 +707,7 @@ static int ohci_hub_control ( &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_RESET: - root_port_reset (ohci, wIndex); + retval = root_port_reset (ohci, wIndex); break; default: goto error; diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index e121d97ed91..e9807cf73a2 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -38,7 +38,7 @@ static void lh7a404_start_hc(struct platform_device *dev) CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */ udelay(1000); USBH_CMDSTATUS = OHCI_HCR; - + printk(KERN_DEBUG __FILE__ ": Clock to USB host has been enabled \n"); } @@ -89,7 +89,7 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver, retval = -EBUSY; goto err1; } - + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { pr_debug("ioremap failed"); @@ -174,7 +174,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .start = ohci_lh7a404_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -242,7 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_lh7a404_driver = { .probe = ohci_hcd_lh7a404_drv_probe, .remove = ohci_hcd_lh7a404_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_lh7a404_drv_suspend, */ /*.resume = ohci_hcd_lh7a404_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index d976614eebd..2f20d3dc895 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -1,24 +1,24 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * + * * This file is licenced under the GPL. */ /*-------------------------------------------------------------------------*/ /* - * There's basically three types of memory: + * OHCI deals with three types of memory: * - data used only by the HCD ... kmalloc is fine * - async and periodic schedules, shared by HC and HCD ... these * need to use dma_pool or dma_alloc_coherent * - driver buffers, read/written by HC ... the hcd glue or the * device driver provides us with dma addresses * - * There's also PCI "register" data, which is memory mapped. - * No memory seen by this driver is pagable. + * There's also "register" data, which is memory mapped. + * No memory seen by this driver (or any HCD) may be paged out. */ /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 9c02177de50..27be1f93688 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -447,7 +447,7 @@ static const struct hc_driver ohci_omap_hc_driver = { .reset = ohci_omap_init, .start = ohci_omap_start, .stop = ohci_omap_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -533,7 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev) static struct platform_driver ohci_hcd_omap_driver = { .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_omap_suspend, .resume = ohci_omap_resume, diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 87441855278..596e0b41e60 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -3,17 +3,17 @@ * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * + * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] * [ (C) Copyright 1999 Linus Torvalds ] * [ (C) Copyright 1999 Gregory P. Smith] - * + * * PCI Bus Glue * * This file is licenced under the GPL. */ - + #ifndef CONFIG_PCI #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif @@ -83,7 +83,7 @@ ohci_pci_start (struct usb_hcd *hcd) pci_dev_put(b); } - /* Check for Compaq's ZFMicro chipset, which needs short + /* Check for Compaq's ZFMicro chipset, which needs short * delays before control or bulk queues get re-activated * in finish_unlinks() */ @@ -238,8 +238,8 @@ static struct pci_driver ohci_pci_driver = { .shutdown = usb_hcd_pci_shutdown, }; - -static int __init ohci_hcd_pci_init (void) + +static int __init ohci_hcd_pci_init (void) { printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); if (usb_disabled()) @@ -253,8 +253,8 @@ module_init (ohci_hcd_pci_init); /*-------------------------------------------------------------------------*/ -static void __exit ohci_hcd_pci_cleanup (void) -{ +static void __exit ohci_hcd_pci_cleanup (void) +{ pci_unregister_driver (&ohci_pci_driver); } module_exit (ohci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 7f26f9bdbaf..3a8cbfb6905 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -4,7 +4,7 @@ * driver for Philips PNX4008 USB Host * * Authors: Dmitry Chigirev <source@mvista.com> - * Vitaly Wool <vitalywool@gmail.com> + * Vitaly Wool <vitalywool@gmail.com> * * register initialization is based on code examples provided by Philips * Copyright (c) 2005 Koninklijke Philips Electronics N.V. @@ -29,7 +29,7 @@ #include <asm/arch/irqs.h> #include <asm/arch/gpio.h> -#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64) +#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64) /* USB_CTRL bit defines */ #define USB_SLAVE_HCLK_EN (1 << 24) diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c new file mode 100644 index 00000000000..6922b91b170 --- /dev/null +++ b/drivers/usb/host/ohci-pnx8550.c @@ -0,0 +1,258 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2005 Embedded Alley Solutions, Inc. + * + * Bus Glue for PNX8550 + * + * Written by Christopher Hoover <ch@hpl.hp.com> + * Based on fragments of previous driver by Russell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta <pattamattad@sharpsec.com> + * + * Modified for PNX8550 from ohci-sa1111.c and sa-omap.c + * by Vitaly Wool <vitalywool@gmail.com> + * + * This file is licenced under the GPL. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <asm/mach-pnx8550/usb.h> +#include <asm/mach-pnx8550/int.h> +#include <asm/mach-pnx8550/pci.h> + +#ifndef CONFIG_PNX8550 +#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined." +#endif + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void pnx8550_start_hc(struct platform_device *dev) +{ + /* + * Set register CLK48CTL to enable and 48MHz + */ + outl(0x00000003, PCI_BASE | 0x0004770c); + + /* + * Set register CLK12CTL to enable and 48MHz + */ + outl(0x00000003, PCI_BASE | 0x00047710); + + udelay(100); +} + +static void pnx8550_stop_hc(struct platform_device *dev) +{ + udelay(10); +} + + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + + +/** + * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + */ +int usb_hcd_pnx8550_probe (const struct hc_driver *driver, + struct platform_device *dev) +{ + int retval; + struct usb_hcd *hcd; + + if (dev->resource[0].flags != IORESOURCE_MEM || + dev->resource[1].flags != IORESOURCE_IRQ) { + dev_err (&dev->dev,"invalid resource type\n"); + return -ENOMEM; + } + + hcd = usb_create_hcd (driver, &dev->dev, "pnx8550"); + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = dev->resource[0].start; + hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] " + "failed\n", hcd->rsrc_start, hcd->rsrc_len); + retval = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n", + hcd->rsrc_start, hcd->rsrc_len); + retval = -ENOMEM; + goto err2; + } + + pnx8550_start_hc(dev); + + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); + if (retval == 0) + return retval; + + pnx8550_stop_hc(dev); + iounmap(hcd->regs); + err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + err1: + usb_put_hcd(hcd); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev) +{ + usb_remove_hcd(hcd); + pnx8550_stop_hc(dev); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); +} + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_pnx8550_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci); + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run (ohci)) < 0) { + err ("can't start %s", hcd->self.bus_name); + ohci_stop (hcd); + return ret; + } + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_pnx8550_hc_driver = { + .description = hcd_name, + .product_desc = "PNX8550 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_pnx8550_start, + .stop = ohci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev) +{ + int ret; + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev); + return ret; +} + +static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_hcd_pnx8550_remove(hcd, pdev); + return 0; +} + +MODULE_ALIAS("pnx8550-ohci"); + +static struct platform_driver ohci_hcd_pnx8550_driver = { + .driver = { + .name = "pnx8550-ohci", + }, + .probe = ohci_hcd_pnx8550_drv_probe, + .remove = ohci_hcd_pnx8550_drv_remove, +}; + +static int __init ohci_hcd_pnx8550_init (void) +{ + pr_debug (DRIVER_INFO " (pnx8550)"); + pr_debug ("block sizes: ed %d td %d\n", + sizeof (struct ed), sizeof (struct td)); + + return platform_driver_register(&ohci_hcd_pnx8550_driver); +} + +static void __exit ohci_hcd_pnx8550_cleanup (void) +{ + platform_driver_unregister(&ohci_hcd_pnx8550_driver); +} + +module_init (ohci_hcd_pnx8550_init); +module_exit (ohci_hcd_pnx8550_cleanup); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index d9d1ae236bd..e1a7eb81731 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -5,7 +5,7 @@ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> * (C) Copyright 2002 Hewlett-Packard Company * (C) Copyright 2003-2005 MontaVista Software Inc. - * + * * Bus Glue for PPC On-Chip OHCI driver * Tested on Freescale MPC5200 and IBM STB04xxx * @@ -85,7 +85,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: - usb_put_hcd(hcd); + usb_put_hcd(hcd); return retval; } @@ -148,7 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .start = ohci_ppc_soc_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -197,7 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) static struct platform_driver ohci_hcd_ppc_soc_driver = { .probe = ohci_hcd_ppc_soc_drv_probe, .remove = ohci_hcd_ppc_soc_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index e176b04d7ae..3bbea844a9e 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -47,7 +47,7 @@ static int pxa27x_ohci_select_pmm( int mode ) switch ( mode ) { case PMM_NPS_MODE: UHCRHDA |= RH_A_NPS; - break; + break; case PMM_GLOBAL_MODE: UHCRHDA &= ~(RH_A_NPS & RH_A_PSM); break; @@ -60,7 +60,7 @@ static int pxa27x_ohci_select_pmm( int mode ) break; default: printk( KERN_ERR - "Invalid mode %d, set to non-power switch mode.\n", + "Invalid mode %d, set to non-power switch mode.\n", mode ); UHCRHDA |= RH_A_NPS; @@ -270,7 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .start = ohci_pxa27x_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -359,9 +359,9 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev) static struct platform_driver ohci_hcd_pxa27x_driver = { .probe = ohci_hcd_pxa27x_drv_probe, .remove = ohci_hcd_pxa27x_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM - .suspend = ohci_hcd_pxa27x_drv_suspend, + .suspend = ohci_hcd_pxa27x_drv_suspend, .resume = ohci_hcd_pxa27x_drv_resume, #endif .driver = { diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index fe1fe2f97cb..830a3fe8615 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * + * * This file is licenced under the GPL. */ @@ -89,7 +89,7 @@ __acquires(ohci->lock) /*-------------------------------------------------------------------------* * ED handling functions - *-------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------*/ /* search for the right schedule branch to use for a periodic ed. * does some load balancing; returns the branch, or negative errno. @@ -107,7 +107,6 @@ static int balance (struct ohci_hcd *ohci, int interval, int load) */ for (i = 0; i < interval ; i++) { if (branch < 0 || ohci->load [branch] > ohci->load [i]) { -#if 1 /* CONFIG_USB_BANDWIDTH */ int j; /* usb 1.1 says 90% of one frame */ @@ -117,8 +116,7 @@ static int balance (struct ohci_hcd *ohci, int interval, int load) } if (j < NUM_INTS) continue; -#endif - branch = i; + branch = i; } } return branch; @@ -171,7 +169,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) /* link an ed into one of the HC chains */ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) -{ +{ int branch; if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING) @@ -248,7 +246,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) } ed->branch = branch; periodic_link (ohci, ed); - } + } /* the HC may not see the schedule updates yet, but if it does * then they'll be properly ordered. @@ -277,7 +275,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) *prev = ed->ed_next; } ohci->load [i] -= ed->load; - } + } ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval; ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", @@ -285,7 +283,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) ed, ed->branch, ed->load, ed->interval); } -/* unlink an ed from one of the HC chains. +/* unlink an ed from one of the HC chains. * just the link to the ed is unlinked. * the link from the ed still points to another operational ed or 0 * so the HC can eventually finish the processing of the unlinked ed @@ -307,7 +305,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) * When finish_unlinks() runs later, after SOF interrupt, it will often * complete one or more URB unlinks before making that state change. */ -static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) +static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) { ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); wmb (); @@ -397,7 +395,7 @@ static struct ed *ed_get ( unsigned int pipe, int interval ) { - struct ed *ed; + struct ed *ed; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); @@ -413,9 +411,9 @@ static struct ed *ed_get ( goto done; } - /* dummy td; end of td list for ed */ + /* dummy td; end of td list for ed */ td = td_alloc (ohci, GFP_ATOMIC); - if (!td) { + if (!td) { /* out of memory */ ed_free (ohci, ed); ed = NULL; @@ -462,7 +460,7 @@ static struct ed *ed_get ( done: spin_unlock_irqrestore (&ohci->lock, flags); - return ed; + return ed; } /*-------------------------------------------------------------------------*/ @@ -474,7 +472,7 @@ done: * and that ed->state is ED_OPER */ static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ +{ ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE); ed_deschedule (ohci, ed); @@ -541,7 +539,7 @@ td_fill (struct ohci_hcd *ohci, u32 info, td->ed = urb_priv->ed; td->next_dl_td = NULL; td->index = index; - td->urb = urb; + td->urb = urb; td->data_dma = data; if (!len) data = 0; @@ -553,8 +551,8 @@ td_fill (struct ohci_hcd *ohci, u32 info, (data & 0x0FFF) | 0xE000); td->ed->last_iso = info & 0xffff; } else { - td->hwCBP = cpu_to_hc32 (ohci, data); - } + td->hwCBP = cpu_to_hc32 (ohci, data); + } if (data) td->hwBE = cpu_to_hc32 (ohci, data + len - 1); else @@ -597,7 +595,7 @@ static void td_submit_urb ( * use the device toggle bits for resetting, and rely on the fact * that resetting toggle is meaningless if the endpoint is active. */ - if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { + if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out, 1); urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); @@ -721,16 +719,16 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ - if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + if (tdINFO & TD_ISO) { + u16 tdPSW = ohci_hwPSW (ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that * only the first of 0..MAXPSW psws is used. */ - cc = (tdPSW >> 12) & 0xF; - if (tdINFO & TD_CC) /* hc didn't touch? */ + cc = (tdPSW >> 12) & 0xF; + if (tdINFO & TD_CC) /* hc didn't touch? */ return; if (usb_pipeout (urb->pipe)) @@ -758,7 +756,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) int type = usb_pipetype (urb->pipe); u32 tdBE = hc32_to_cpup (ohci, &td->hwBE); - cc = TD_CC_GET (tdINFO); + cc = TD_CC_GET (tdINFO); /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN @@ -787,7 +785,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb, td, 1 + td->index, cc, urb->actual_length, urb->transfer_buffer_length); - } + } } /*-------------------------------------------------------------------------*/ @@ -795,7 +793,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) static inline struct td * ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) { - struct urb *urb = td->urb; + struct urb *urb = td->urb; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -805,7 +803,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) */ ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); wmb (); - ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); + ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); /* put any later tds from this urb onto the donelist, after 'td', * order won't matter here: no errors, and nothing was transferred. @@ -833,7 +831,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) info &= ~cpu_to_hc32 (ohci, TD_CC); next->hwINFO = info; - next->next_dl_td = rev; + next->next_dl_td = rev; rev = next; ed->hwHeadP = next->hwNextTD | toggle; @@ -881,8 +879,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) /* get TD from hc's singly linked list, and * prepend to ours. ed->td_list changes later. */ - while (td_dma) { - int cc; + while (td_dma) { + int cc; td = dma_to_td (ohci, td_dma); if (!td) { @@ -901,10 +899,10 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) td_rev = ed_halted (ohci, td, cc, td_rev); - td->next_dl_td = td_rev; + td->next_dl_td = td_rev; td_rev = td; td_dma = hc32_to_cpup (ohci, &td->hwNextTD); - } + } return td_rev; } @@ -1013,9 +1011,9 @@ rescan_this: if (modified) goto rescan_all; - } + } - /* maybe reenable control and bulk lists */ + /* maybe reenable control and bulk lists */ if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state) && ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING && !ohci->ed_rm_list) { @@ -1041,20 +1039,20 @@ rescan_this: &ohci->regs->ed_bulkcurrent); } } - + /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; if (ohci->flags & OHCI_QUIRK_ZFMICRO) mdelay(1); - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - } + ohci_writel (ohci, ohci->hc_control, + &ohci->regs->control); + } if (command) { if (ohci->flags & OHCI_QUIRK_ZFMICRO) mdelay(1); - ohci_writel (ohci, command, &ohci->regs->cmdstatus); - } + ohci_writel (ohci, command, &ohci->regs->cmdstatus); + } } } @@ -1074,19 +1072,19 @@ dl_done_list (struct ohci_hcd *ohci) { struct td *td = dl_reverse_done_list (ohci); - while (td) { + while (td) { struct td *td_next = td->next_dl_td; struct urb *urb = td->urb; urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; + td_done (ohci, urb, td); + urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); + if (urb_priv->td_cnt == urb_priv->length) + finish_urb (ohci, urb); /* clean schedule: unlink EDs that are no longer busy */ if (list_empty (&ed->td_list)) { @@ -1094,25 +1092,26 @@ dl_done_list (struct ohci_hcd *ohci) start_ed_unlink (ohci, ed); /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE)) + } else if ((ed->hwINFO & cpu_to_hc32 (ohci, + ED_SKIP | ED_DEQUEUE)) == cpu_to_hc32 (ohci, ED_SKIP)) { td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { + if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); /* ... hc may need waking-up */ switch (ed->type) { case PIPE_CONTROL: ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); + &ohci->regs->cmdstatus); break; case PIPE_BULK: ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); + &ohci->regs->cmdstatus); break; } } } - td = td_next; - } + td = td_next; + } } diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 59e436424d4..b350d45033e 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -447,7 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .start = ohci_s3c2410_start, .stop = ohci_stop, - .shutdown = ohci_shutdown, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -492,7 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev) static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, - .shutdown = usb_hcd_platform_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ /*.resume = ohci_hcd_s3c2410_drv_resume, */ .driver = { diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 71371de32ad..fe0090e3367 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -4,7 +4,7 @@ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> * (C) Copyright 2002 Hewlett-Packard Company - * + * * SA1111 Bus Glue * * Written by Christopher Hoover <ch@hpl.hp.com> @@ -12,7 +12,7 @@ * * This file is licenced under the GPL. */ - + #include <asm/hardware.h> #include <asm/mach-types.h> #include <asm/arch/assabet.h> @@ -31,7 +31,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev) { unsigned int usb_rst = 0; - printk(KERN_DEBUG __FILE__ + printk(KERN_DEBUG __FILE__ ": starting SA-1111 OHCI USB Controller\n"); #ifdef CONFIG_SA1100_BADGE4 @@ -65,7 +65,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev) static void sa1111_stop_hc(struct sa1111_dev *dev) { unsigned int usb_rst; - printk(KERN_DEBUG __FILE__ + printk(KERN_DEBUG __FILE__ ": stopping SA-1111 OHCI USB Controller\n"); /* diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index a2f42a2f47c..405257f3e85 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * + * * This file is licenced under the GPL. */ @@ -14,7 +14,7 @@ */ typedef __u32 __bitwise __hc32; typedef __u16 __bitwise __hc16; - + /* * OHCI Endpoint Descriptor (ED) ... holds TD queue * See OHCI spec, section 4.2 @@ -24,7 +24,7 @@ typedef __u16 __bitwise __hc16; */ struct ed { /* first fields are hardware-specified */ - __hc32 hwINFO; /* endpoint config bitmap */ + __hc32 hwINFO; /* endpoint config bitmap */ /* info bits defined by hcd */ #define ED_DEQUEUE (1 << 27) /* info bits defined by the hardware */ @@ -52,11 +52,11 @@ struct ed { * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... */ u8 state; /* ED_{IDLE,UNLINK,OPER} */ -#define ED_IDLE 0x00 /* NOT linked to HC */ -#define ED_UNLINK 0x01 /* being unlinked from hc */ +#define ED_IDLE 0x00 /* NOT linked to HC */ +#define ED_UNLINK 0x01 /* being unlinked from hc */ #define ED_OPER 0x02 /* IS linked to hc */ - u8 type; /* PIPE_{BULK,...} */ + u8 type; /* PIPE_{BULK,...} */ /* periodic scheduling params (for intr and iso) */ u8 branch; @@ -70,7 +70,7 @@ struct ed { #define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ - + /* * OHCI Transfer Descriptor (TD) ... one per transfer segment * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) @@ -107,22 +107,22 @@ struct td { /* (no hwINFO #defines yet for iso tds) */ - __hc32 hwCBP; /* Current Buffer Pointer (or 0) */ - __hc32 hwNextTD; /* Next TD Pointer */ - __hc32 hwBE; /* Memory Buffer End Pointer */ + __hc32 hwCBP; /* Current Buffer Pointer (or 0) */ + __hc32 hwNextTD; /* Next TD Pointer */ + __hc32 hwBE; /* Memory Buffer End Pointer */ /* PSW is only for ISO. Only 1 PSW entry is used, but on * big-endian PPC hardware that's the second entry. */ #define MAXPSW 2 - __hc16 hwPSW [MAXPSW]; + __hc16 hwPSW [MAXPSW]; /* rest are purely for the driver's use */ - __u8 index; - struct ed *ed; - struct td *td_hash; /* dma-->td hashtable */ - struct td *next_dl_td; - struct urb *urb; + __u8 index; + struct ed *ed; + struct td *td_hash; /* dma-->td hashtable */ + struct td *next_dl_td; + struct urb *urb; dma_addr_t td_dma; /* addr of this TD */ dma_addr_t data_dma; /* addr of data it points to */ @@ -152,8 +152,8 @@ struct td { #define TD_NOTACCESSED 0x0F -/* map OHCI TD status codes (CC) to errno values */ -static const int cc_to_error [16] = { +/* map OHCI TD status codes (CC) to errno values */ +static const int cc_to_error [16] = { /* No Error */ 0, /* CRC Error */ -EILSEQ, /* Bit Stuff */ -EPROTO, @@ -169,7 +169,7 @@ static const int cc_to_error [16] = { /* BufferOver */ -ECOMM, /* BuffUnder */ -ENOSR, /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY + /* (for HCD) */ -EALREADY }; @@ -182,7 +182,7 @@ struct ohci_hcca { #define NUM_INTS 32 __hc32 int_table [NUM_INTS]; /* periodic schedule */ - /* + /* * OHCI defines u16 frame_no, followed by u16 zero pad. * Since some processors can't do 16 bit bus accesses, * portable access must be a 32 bits wide. @@ -262,10 +262,10 @@ struct ohci_regs { * HcCommandStatus (cmdstatus) register masks */ #define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_CLF (1 << 1) /* control list filled */ -#define OHCI_BLF (1 << 2) /* bulk list filled */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ +#define OHCI_CLF (1 << 1) /* control list filled */ +#define OHCI_BLF (1 << 2) /* bulk list filled */ +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_SOC (3 << 16) /* scheduling overrun count */ /* * masks used with interrupt registers: @@ -285,20 +285,20 @@ struct ohci_regs { /* OHCI ROOT HUB REGISTER MASKS */ - + /* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ +#define RH_PS_CCS 0x00000001 /* current connect status */ +#define RH_PS_PES 0x00000002 /* port enable status*/ +#define RH_PS_PSS 0x00000004 /* port suspend status */ +#define RH_PS_POCI 0x00000008 /* port over current indicator */ +#define RH_PS_PRS 0x00000010 /* port reset status */ +#define RH_PS_PPS 0x00000100 /* port power status */ +#define RH_PS_LSDA 0x00000200 /* low speed device attached */ +#define RH_PS_CSC 0x00010000 /* connect status change */ +#define RH_PS_PESC 0x00020000 /* port enable status change */ +#define RH_PS_PSSC 0x00040000 /* port suspend status change */ +#define RH_PS_OCIC 0x00080000 /* over current indicator change */ +#define RH_PS_PRSC 0x00100000 /* port reset status change */ /* roothub.status bits */ #define RH_HS_LPS 0x00000001 /* local power status */ @@ -333,7 +333,7 @@ typedef struct urb_priv { } urb_priv_t; #define TD_HASH_SIZE 64 /* power'o'two */ -// sizeof (struct td) ~= 64 == 2^6 ... +// sizeof (struct td) ~= 64 == 2^6 ... #define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) @@ -364,11 +364,11 @@ struct ohci_hcd { struct ed *ed_bulktail; /* last in bulk list */ struct ed *ed_controltail; /* last in ctrl list */ - struct ed *periodic [NUM_INTS]; /* shadow int_table */ + struct ed *periodic [NUM_INTS]; /* shadow int_table */ /* * OTG controllers and transceivers need software interaction; - * other external transceivers should be software-transparent + * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; @@ -385,7 +385,7 @@ struct ohci_hcd { */ int num_ports; int load [NUM_INTS]; - u32 hc_control; /* copy of hc control reg */ + u32 hc_control; /* copy of hc control reg */ unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ unsigned autostop:1; /* rh auto stopping/stopped */ @@ -598,11 +598,11 @@ static inline void disable (struct ohci_hcd *ohci) } #define FI 0x2edf /* 12000 bits per frame (-1) */ -#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) +#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) #define FIT (1 << 31) #define LSTHRESH 0x628 /* lowspeed bit threshold */ -static void periodic_reinit (struct ohci_hcd *ohci) +static inline void periodic_reinit (struct ohci_hcd *ohci) { u32 fi = ohci->fminterval & 0x03fff; u32 fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT; @@ -626,11 +626,11 @@ static void periodic_reinit (struct ohci_hcd *ohci) temp = ohci_readl (hc, &hc->regs->roothub.register); \ temp; }) -static u32 roothub_a (struct ohci_hcd *hc) +static inline u32 roothub_a (struct ohci_hcd *hc) { return read_roothub (hc, a, 0xfc0fe000); } static inline u32 roothub_b (struct ohci_hcd *hc) { return ohci_readl (hc, &hc->regs->roothub.b); } static inline u32 roothub_status (struct ohci_hcd *hc) { return ohci_readl (hc, &hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci_hcd *hc, int i) +static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i) { return read_roothub (hc, portstatus [i], 0xffe0fce0); } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index a9d7119e317..a7fa0d75567 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -40,6 +40,7 @@ #include <linux/moduleparam.h> #include <linux/delay.h> #include <linux/ioport.h> +#include <linux/pci_ids.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> @@ -210,15 +211,16 @@ struct u132 { * these cannot be inlines because we need the structure offset!! * Does anyone have a better way????? */ +#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \ + offsetof(struct ohci_regs, member), 0, data); +#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \ + offsetof(struct ohci_regs, member), 0, data); #define u132_read_pcimem(u132, member, data) \ usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \ ohci_regs, member), 0, data); #define u132_write_pcimem(u132, member, data) \ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ ohci_regs, member), 0, data); -#define u132_write_pcimem_byte(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0x0e, data); static inline struct u132 *udev_to_u132(struct u132_udev *udev) { u8 udev_number = udev->udev_number; @@ -1574,59 +1576,12 @@ static char *hcfs2string(int state) return "?"; } -static int u132_usb_reset(struct u132 *u132) -{ - int retval; - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - u132->hc_control &= OHCI_CTRL_RWC; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - return 0; -} - static int u132_init(struct u132 *u132) { int retval; u32 control; u132_disable(u132); - u132->next_statechange = - jiffies; /* SMM owns the HC? not for long! */ { - u32 control; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (control & OHCI_CTRL_IR) { - u32 temp = 50; - retval = u132_write_pcimem(u132, intrenable, - OHCI_INTR_OC); - if (retval) - return retval; - retval = u132_write_pcimem_byte(u132, cmdstatus, - OHCI_OCR); - if (retval) - return retval; - check:{ - retval = u132_read_pcimem(u132, control, - &control); - if (retval) - return retval; - } - if (control & OHCI_CTRL_IR) { - msleep(10); - if (--temp == 0) { - dev_err(&u132->platform_dev->dev, "USB " - "HC takeover failed!(BIOS/SMM b" - "ug) control=%08X\n", control); - return -EBUSY; - } - goto check; - } - u132_usb_reset(u132); - } - } + u132->next_statechange = jiffies; retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); if (retval) return retval; @@ -1725,7 +1680,7 @@ static int u132_run(struct u132 *u132) retry:retval = u132_read_pcimem(u132, cmdstatus, &status); if (retval) return retval; - retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR); + retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); if (retval) return retval; extra:{ @@ -1782,7 +1737,7 @@ static int u132_run(struct u132 *u132) retval = u132_write_pcimem(u132, control, u132->hc_control); if (retval) return retval; - retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF); + retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); if (retval) return retval; retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); @@ -1839,8 +1794,8 @@ static void u132_hcd_stop(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" + "een removed %d\n", u132, hcd, u132->going); } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); @@ -2545,8 +2500,9 @@ static void u132_endpoint_disable(struct usb_hcd *hcd, { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" + ") has been removed %d\n", u132, hcd, hep, + u132->going); } else { struct u132_endp *endp = hep->hcpriv; if (endp) @@ -2790,7 +2746,6 @@ static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); - dump_stack(); return -ESHUTDOWN; } else { int i, changed = 0, length = 1; @@ -3034,12 +2989,15 @@ static int __devexit u132_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); if (hcd) { struct u132 *u132 = hcd_to_u132(hcd); - dump_stack(); if (u132->going++ > 1) { + dev_err(&u132->platform_dev->dev, "already being remove" + "d\n"); return -ENODEV; } else { int rings = MAX_U132_RINGS; int endps = MAX_U132_ENDPS; + dev_err(&u132->platform_dev->dev, "removing device u132" + ".%d\n", u132->sequence_num); msleep(100); down(&u132->sw_lock); u132_monitor_cancel_work(u132); @@ -3121,10 +3079,24 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) static int __devinit u132_probe(struct platform_device *pdev) { struct usb_hcd *hcd; + int retval; + u32 control; + u32 rh_a = -1; + u32 num_ports; msleep(100); if (u132_exiting > 0) { return -ENODEV; - } /* refuse to confuse usbcore */ + } + retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); + if (retval) + return retval; + retval = ftdi_read_pcimem(pdev, control, &control); + if (retval) + return retval; + retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); + if (retval) + return retval; + num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */ if (pdev->dev.dma_mask) { return -EINVAL; } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e87692c31be..e0d4c2358b3 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -60,6 +60,11 @@ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ Alan Stern" #define DRIVER_DESC "USB Universal Host Controller Interface driver" +/* for flakey hardware, ignore overcurrent indicators */ +static int ignore_oc; +module_param(ignore_oc, bool, S_IRUGO); +MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); + /* * debug = 0, no debugging messages * debug = 1, dump failed URBs except for stalls @@ -169,6 +174,11 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) { int port; + /* If we have to ignore overcurrent events then almost by definition + * we can't depend on resume-detect interrupts. */ + if (ignore_oc) + return 1; + switch (to_pci_dev(uhci_dev(uhci))->vendor) { default: break; @@ -199,24 +209,16 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) static int remote_wakeup_is_broken(struct uhci_hcd *uhci) { - static struct dmi_system_id broken_wakeup_table[] = { - { - .ident = "Asus A7V8X", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"), - DMI_MATCH(DMI_BOARD_NAME, "A7V8X"), - DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"), - } - }, - { } - }; int port; + char *sys_info; + static char bad_Asus_board[] = "A7V8X"; /* One of Asus's motherboards has a bug which causes it to * wake up immediately from suspend-to-RAM if any of the ports * are connected. In such cases we will not set EGSM. */ - if (dmi_check_system(broken_wakeup_table)) { + sys_info = dmi_get_system_info(DMI_BOARD_NAME); + if (sys_info && !strcmp(sys_info, bad_Asus_board)) { for (port = 0; port < uhci->rh_numports; ++port) { if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & USBPORTSC_CCS) @@ -255,7 +257,9 @@ __acquires(uhci->lock) int_enable = USBINTR_RESUME; if (remote_wakeup_is_broken(uhci)) egsm_enable = 0; - if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable) + if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable || + !device_may_wakeup( + &uhci_to_hcd(uhci)->self.root_hub->dev)) uhci->working_RD = int_enable = 0; outw(int_enable, uhci->io_addr + USBINTR); @@ -921,7 +925,8 @@ static int __init uhci_hcd_init(void) { int retval = -ENOMEM; - printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n"); + printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s\n", + ignore_oc ? ", overcurrent ignored" : ""); if (usb_disabled()) return -ENODEV; diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index f8347f1a10b..bacc25c53ba 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -52,10 +52,20 @@ static int any_ports_active(struct uhci_hcd *uhci) static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) { int port; + int mask = RWC_BITS; + + /* Some boards (both VIA and Intel apparently) report bogus + * overcurrent indications, causing massive log spam unless + * we completely ignore them. This doesn't seem to be a problem + * with the chipset so much as with the way it is connected on + * the motherboard; if the overcurrent input is left to float + * then it may constantly register false positives. */ + if (ignore_oc) + mask &= ~USBPORTSC_OCC; *buf = 0; for (port = 0; port < uhci->rh_numports; ++port) { - if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || + if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & mask) || test_bit(port, &uhci->port_c_suspend)) *buf |= (1 << (port + 1)); } @@ -263,7 +273,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wPortChange |= USB_PORT_STAT_C_CONNECTION; if (status & USBPORTSC_PEC) wPortChange |= USB_PORT_STAT_C_ENABLE; - if (status & USBPORTSC_OCC) + if ((status & USBPORTSC_OCC) && !ignore_oc) wPortChange |= USB_PORT_STAT_C_OVERCURRENT; if (test_bit(port, &uhci->port_c_suspend)) { diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 8a62d478575..c7d887540d8 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -7,14 +7,13 @@ comment "USB Input Devices" config USB_HID tristate "USB Human Interface Device (full HID) support" default y - depends on USB && HID + depends on USB && INPUT + select HID ---help--- Say Y here if you want full HID support to connect USB keyboards, mice, joysticks, graphic tablets, or any other HID based devices - to your computer via USB. You also need to select HID Input layer - support (below) if you want to use keyboards, mice, joysticks and - the like ... as well as Uninterruptible Power Supply (UPS) and - monitor control devices. + to your computer via USB, as well as Uninterruptible Power Supply + (UPS) and monitor control devices. You can't use this driver and the HIDBP (Boot Protocol) keyboard and mouse drivers at the same time. More information is available: @@ -28,7 +27,7 @@ config USB_HID comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB_HID && INPUT=n -config USB_HID_POWERBOOK +config USB_HIDINPUT_POWERBOOK bool "Enable support for iBook/PowerBook special keys" default n depends on USB_HID diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 89fa6885709..c6c9e72e5fd 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -56,11 +56,6 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -static int usbhid_pb_fnmode = 1; -module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - /* * Input submission and I/O error handler. */ @@ -106,18 +101,18 @@ static void hid_reset(struct work_struct *work) if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { dev_dbg(&usbhid->intf->dev, "clear halt\n"); - rc = usb_clear_halt(to_usb_device(hid->dev), usbhid->urbin->pipe); + rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe); clear_bit(HID_CLEAR_HALT, &usbhid->iofl); hid_start_in(hid); } else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { dev_dbg(&usbhid->intf->dev, "resetting device\n"); - rc = rc_lock = usb_lock_device_for_reset(to_usb_device(hid->dev), usbhid->intf); + rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf); if (rc_lock >= 0) { - rc = usb_reset_composite_device(to_usb_device(hid->dev), usbhid->intf); + rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf); if (rc_lock) - usb_unlock_device(to_usb_device(hid->dev)); + usb_unlock_device(hid_to_usb_dev(hid)); } clear_bit(HID_RESET_PENDING, &usbhid->iofl); } @@ -129,8 +124,8 @@ static void hid_reset(struct work_struct *work) break; default: err("can't reset device, %s-%s/input%d, status %d", - to_usb_device(hid->dev)->bus->bus_name, - to_usb_device(hid->dev)->devpath, + hid_to_usb_dev(hid)->bus->bus_name, + hid_to_usb_dev(hid)->devpath, usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: @@ -217,8 +212,8 @@ static void hid_irq_in(struct urb *urb) clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err("can't resubmit intr, %s-%s/input%d, status %d", - to_usb_device(hid->dev)->bus->bus_name, - to_usb_device(hid->dev)->devpath, + hid_to_usb_dev(hid)->bus->bus_name, + hid_to_usb_dev(hid)->devpath, usbhid->ifnum, status); hid_io_error(hid); } @@ -251,7 +246,7 @@ static int hid_submit_out(struct hid_device *hid) hid_output_report(report, usbhid->outbuf); usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - usbhid->urbout->dev = to_usb_device(hid->dev); + usbhid->urbout->dev = hid_to_usb_dev(hid); dbg("submitting out urb"); @@ -276,13 +271,13 @@ static int hid_submit_ctrl(struct hid_device *hid) len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { hid_output_report(report, usbhid->ctrlbuf); - usbhid->urbctrl->pipe = usb_sndctrlpipe(to_usb_device(hid->dev), 0); + usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); usbhid->urbctrl->transfer_buffer_length = len; } else { int maxpacket, padlen; - usbhid->urbctrl->pipe = usb_rcvctrlpipe(to_usb_device(hid->dev), 0); - maxpacket = usb_maxpacket(to_usb_device(hid->dev), usbhid->urbctrl->pipe, 0); + usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0); + maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0); if (maxpacket > 0) { padlen = (len + maxpacket - 1) / maxpacket; padlen *= maxpacket; @@ -292,7 +287,7 @@ static int hid_submit_ctrl(struct hid_device *hid) padlen = 0; usbhid->urbctrl->transfer_buffer_length = padlen; } - usbhid->urbctrl->dev = to_usb_device(hid->dev); + usbhid->urbctrl->dev = hid_to_usb_dev(hid); usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; @@ -582,6 +577,7 @@ void usbhid_init_reports(struct hid_device *hid) } #define USB_VENDOR_ID_GTCO 0x078c +#define USB_VENDOR_ID_GTCO_IPANEL_2 0x5543 #define USB_DEVICE_ID_GTCO_90 0x0090 #define USB_DEVICE_ID_GTCO_100 0x0100 #define USB_DEVICE_ID_GTCO_101 0x0101 @@ -627,6 +623,8 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_GTCO_1004 0x1004 #define USB_DEVICE_ID_GTCO_1005 0x1005 #define USB_DEVICE_ID_GTCO_1006 0x1006 +#define USB_DEVICE_ID_GTCO_8 0x0008 +#define USB_DEVICE_ID_GTCO_d 0x000d #define USB_VENDOR_ID_WACOM 0x056a @@ -791,6 +789,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 +#define USB_VENDOR_ID_IMATION 0x0718 +#define USB_DEVICE_ID_DISC_STAKKA 0xd000 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -875,6 +876,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE }, @@ -951,7 +955,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, @@ -1187,7 +1191,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - hid->dev = &dev->dev; + hid->dev = &intf->dev; usbhid->intf = intf; usbhid->ifnum = interface->desc.bInterfaceNumber; @@ -1237,10 +1241,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; #endif -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - hid->pb_fnmode = usbhid_pb_fnmode; -#endif - return hid; fail: @@ -1282,7 +1282,7 @@ static void hid_disconnect(struct usb_interface *intf) usb_free_urb(usbhid->urbctrl); usb_free_urb(usbhid->urbout); - hid_free_buffers(to_usb_device(hid->dev), hid); + hid_free_buffers(hid_to_usb_dev(hid), hid); hid_free_device(hid); } diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index f8f660ee3fa..59ed65e7a62 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -33,6 +33,7 @@ #include <linux/usb.h> #include <linux/hid.h> +#include "usbhid.h" /* * This table contains pointers to initializers. To add support for new @@ -70,8 +71,8 @@ static struct hid_ff_initializer inits[] = { int hid_ff_init(struct hid_device* hid) { struct hid_ff_initializer *init; - int vendor = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idVendor); - int product = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idProduct); + int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor); + int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct); for (init = inits; init->idVendor; init++) if (init->idVendor == vendor && init->idProduct == product) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 114d6c9f64b..a8b3d66cd49 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -384,7 +384,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = to_usb_device(hid->dev); + struct usb_device *dev = hid_to_usb_dev(hid); struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h index 830107e5251..0023f96d429 100644 --- a/drivers/usb/input/usbhid.h +++ b/drivers/usb/input/usbhid.h @@ -80,5 +80,8 @@ struct usbhid_device { }; +#define hid_to_usb_dev(hid_dev) \ + container_of(hid_dev->dev->parent, struct usb_device, dev) + #endif diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index 7f3c57da9bc..86e37a20f8e 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -66,7 +66,7 @@ struct usbtouch_device_info { void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); int (*get_pkt_len) (unsigned char *pkt, int len); - int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press); + int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); int (*init) (struct usbtouch_usb *usbtouch); }; @@ -85,6 +85,9 @@ struct usbtouch_usb { struct usbtouch_device_info *type; char name[128]; char phys[64]; + + int x, y; + int touch, press; }; @@ -161,14 +164,14 @@ static struct usb_device_id usbtouch_devices[] = { #define EGALAX_PKT_TYPE_REPT 0x80 #define EGALAX_PKT_TYPE_DIAG 0x0A -static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) return 0; - *x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); - *y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); - *touch = pkt[0] & 0x01; + dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); + dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); + dev->touch = pkt[0] & 0x01; return 1; } @@ -195,11 +198,11 @@ static int egalax_get_pkt_len(unsigned char *buf, int len) * PanJit Part */ #ifdef CONFIG_USB_TOUCHSCREEN_PANJIT -static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = ((pkt[2] & 0x0F) << 8) | pkt[1]; - *y = ((pkt[4] & 0x0F) << 8) | pkt[3]; - *touch = pkt[0] & 0x01; + dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1]; + dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3]; + dev->touch = pkt[0] & 0x01; return 1; } @@ -215,11 +218,11 @@ static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int #define MTOUCHUSB_RESET 7 #define MTOUCHUSB_REQ_CTRLLR_ID 10 -static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = (pkt[8] << 8) | pkt[7]; - *y = (pkt[10] << 8) | pkt[9]; - *touch = (pkt[2] & 0x40) ? 1 : 0; + dev->x = (pkt[8] << 8) | pkt[7]; + dev->y = (pkt[10] << 8) | pkt[9]; + dev->touch = (pkt[2] & 0x40) ? 1 : 0; return 1; } @@ -260,14 +263,32 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) * ITM Part */ #ifdef CONFIG_USB_TOUCHSCREEN_ITM -static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); - *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); - *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); - *touch = ~pkt[7] & 0x20; + int touch; + /* + * ITM devices report invalid x/y data if not touched. + * if the screen was touched before but is not touched any more + * report touch as 0 with the last valid x/y data once. then stop + * reporting data until touched again. + */ + dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); + + touch = ~pkt[7] & 0x20; + if (!touch) { + if (dev->touch) { + dev->touch = 0; + return 1; + } - return *touch; + return 0; + } + + dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); + dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); + dev->touch = touch; + + return 1; } #endif @@ -276,7 +297,7 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr * eTurboTouch part */ #ifdef CONFIG_USB_TOUCHSCREEN_ETURBO -static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { unsigned int shift; @@ -285,9 +306,9 @@ static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int return 0; shift = (6 - (pkt[0] & 0x03)); - *x = ((pkt[3] << 7) | pkt[4]) >> shift; - *y = ((pkt[1] << 7) | pkt[2]) >> shift; - *touch = (pkt[0] & 0x10) ? 1 : 0; + dev->x = ((pkt[3] << 7) | pkt[4]) >> shift; + dev->y = ((pkt[1] << 7) | pkt[2]) >> shift; + dev->touch = (pkt[0] & 0x10) ? 1 : 0; return 1; } @@ -307,14 +328,14 @@ static int eturbo_get_pkt_len(unsigned char *buf, int len) * Gunze part */ #ifdef CONFIG_USB_TOUCHSCREEN_GUNZE -static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80)) return 0; - *x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F); - *y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F); - *touch = pkt[0] & 0x20; + dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F); + dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F); + dev->touch = pkt[0] & 0x20; return 1; } @@ -383,11 +404,11 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) } -static int dmc_tsc10_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { - *x = ((pkt[2] & 0x03) << 8) | pkt[1]; - *y = ((pkt[4] & 0x03) << 8) | pkt[3]; - *touch = pkt[0] & 0x01; + dev->x = ((pkt[2] & 0x03) << 8) | pkt[1]; + dev->y = ((pkt[4] & 0x03) << 8) | pkt[3]; + dev->touch = pkt[0] & 0x01; return 1; } @@ -492,23 +513,22 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, unsigned char *pkt, int len) { - int x, y, touch, press; struct usbtouch_device_info *type = usbtouch->type; - if (!type->read_data(pkt, &x, &y, &touch, &press)) + if (!type->read_data(usbtouch, pkt)) return; - input_report_key(usbtouch->input, BTN_TOUCH, touch); + input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); if (swap_xy) { - input_report_abs(usbtouch->input, ABS_X, y); - input_report_abs(usbtouch->input, ABS_Y, x); + input_report_abs(usbtouch->input, ABS_X, usbtouch->y); + input_report_abs(usbtouch->input, ABS_Y, usbtouch->x); } else { - input_report_abs(usbtouch->input, ABS_X, x); - input_report_abs(usbtouch->input, ABS_Y, y); + input_report_abs(usbtouch->input, ABS_X, usbtouch->x); + input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); } if (type->max_press) - input_report_abs(usbtouch->input, ABS_PRESSURE, press); + input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press); input_sync(usbtouch->input); } diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index e7cc20ab815..12b42746ded 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -159,13 +159,13 @@ void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); - input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); + input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); } void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); - input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); + input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); } void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index 92726fe8937..4142e36730f 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -209,13 +209,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02); wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04); } - } - - if (data[1] & 0x10) wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */ + } else wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - wacom_report_key(wcombo, wacom->tool[0], data[1] & 0x10); + + if (data[1] & 0x10) /* only report prox-in when in area */ + wacom_report_key(wcombo, wacom->tool[0], 1); + if (!(data[1] & 0x90)) /* report prox-out when physically out */ + wacom_report_key(wcombo, wacom->tool[0], 0); wacom_input_sync(wcombo); /* send pad data */ @@ -405,7 +407,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) return 0; - if (wacom->features->type >= INTUOS3) { + if (wacom->features->type >= INTUOS3S) { wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); @@ -423,7 +425,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (data[1] & 0x02) { /* Rotation packet */ - if (wacom->features->type >= INTUOS3) { + if (wacom->features->type >= INTUOS3S) { /* I3 marker pen rotation reported as wheel * due to valuator limitation */ @@ -547,11 +549,11 @@ static struct wacom_features wacom_features[] = { { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, - { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE }, - { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE }, - { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE }, - { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE }, - { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Volito", 8, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE }, + { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, + { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, + { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE }, { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, @@ -580,7 +582,7 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, - { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S }, + { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { } diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 02cbb7fff24..a7932a72d29 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,7 +281,7 @@ static int appledisplay_probe(struct usb_interface *iface, /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); - pdata->bd = backlight_device_register(bl_name, pdata, + pdata->bd = backlight_device_register(bl_name, NULL, NULL, &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 6c7f3efb1d4..b5332e679c4 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -1376,7 +1376,7 @@ static int auerchar_open (struct inode *inode, struct file *file) } /* we have access to the device. Now lets allocate memory */ - ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); + ccp = kzalloc(sizeof(auerchar_t), GFP_KERNEL); if (ccp == NULL) { err ("out of memory"); ret = -ENOMEM; @@ -1384,7 +1384,6 @@ static int auerchar_open (struct inode *inode, struct file *file) } /* Initialize device descriptor */ - memset( ccp, 0, sizeof(auerchar_t)); init_MUTEX( &ccp->mutex); init_MUTEX( &ccp->readmutex); auerbuf_init (&ccp->bufctl); @@ -1912,14 +1911,13 @@ static int auerswald_probe (struct usb_interface *intf, return -ENODEV; /* allocate memory for our device and initialize it */ - cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL); + cp = kzalloc (sizeof(auerswald_t), GFP_KERNEL); if (cp == NULL) { err ("out of memory"); goto pfail; } /* Initialize device descriptor */ - memset (cp, 0, sizeof(auerswald_t)); init_MUTEX (&cp->mutex); cp->usbdev = usbdev; auerchain_init (&cp->controlchain); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 18b1925032a..41c0161abdb 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -40,6 +40,7 @@ #include <linux/init.h> #include <linux/list.h> #include <linux/ioctl.h> +#include <linux/pci_ids.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/kref.h> @@ -51,6 +52,10 @@ MODULE_AUTHOR("Tony Olech"); MODULE_DESCRIPTION("FTDI ELAN driver"); MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) +static int distrust_firmware = 1; +module_param(distrust_firmware, bool, 0); +MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" + "t setup"); extern struct platform_driver u132_platform_driver; static struct workqueue_struct *status_queue; static struct workqueue_struct *command_queue; @@ -66,7 +71,9 @@ static struct list_head ftdi_static_list; * end of the global variables protected by ftdi_module_lock */ #include "usb_u132.h" -#define TD_DEVNOTRESP 5 +#include <asm/io.h> +#include "../core/hcd.h" +#include "../host/ohci.h" /* Define these values to match your devices*/ #define USB_FTDI_ELAN_VENDOR_ID 0x0403 #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea @@ -551,7 +558,7 @@ static void ftdi_elan_status_work(struct work_struct *work) } else { dev_err(&ftdi->udev->dev, "initialized failed - trying " "again in 10 seconds\n"); - work_delay_in_msec = 10 *1000; + work_delay_in_msec = 1 *1000; } } else if (ftdi->registered == 0) { work_delay_in_msec = 10; @@ -2288,82 +2295,288 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) } } -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) + +#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ + offsetof(struct ohci_regs, member), 0, data); +#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ + offsetof(struct ohci_regs, member), 0, data); +#define OHCI_QUIRK_AMD756 0x01 +#define OHCI_QUIRK_SUPERIO 0x02 +#define OHCI_QUIRK_INITRESET 0x04 +#define OHCI_BIG_ENDIAN 0x08 +#define OHCI_QUIRK_ZFMICRO 0x10 +#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR +#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ + OHCI_INTR_WDH) +static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) +{ + int devices = 0; + int retval; + u32 hc_control; + int num_ports; + u32 control; + u32 rh_a = -1; + u32 status; + u32 fminterval; + u32 hc_fminterval; + u32 periodicstart; + u32 cmdstatus; + u32 roothub_a; + int mask = OHCI_INTR_INIT; + int sleep_time = 0; + int reset_timeout = 30; /* ... allow extra time */ + int temp; + retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); + if (retval) + return retval; + num_ports = rh_a & RH_A_NDP; + retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); + if (retval) + return retval; + hc_fminterval &= 0x3fff; + if (hc_fminterval != FI) { + } + hc_fminterval |= FSMP(hc_fminterval) << 16; + retval = ftdi_read_pcimem(ftdi, control, &hc_control); + if (retval) + return retval; + switch (hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + sleep_time = 0; + break; + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_USB_RESUME; + sleep_time = 10; + break; + default: + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_USB_RESET; + sleep_time = 50; + break; + } + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + msleep(sleep_time); + retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); + if (retval) + return retval; + if (!(roothub_a & RH_A_NPS)) { /* power down each port */ + for (temp = 0; temp < num_ports; temp++) { + retval = ftdi_write_pcimem(ftdi, + roothub.portstatus[temp], RH_PS_LSDA); + if (retval) + return retval; + } + } + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); + if (retval) + return retval; + extra:{ + retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); + if (retval) + return retval; + if (0 != (status & OHCI_HCR)) { + if (--reset_timeout == 0) { + dev_err(&ftdi->udev->dev, "USB HC reset timed o" + "ut!\n"); + return -ENODEV; + } else { + msleep(5); + goto extra; + } + } + } + if (quirk & OHCI_QUIRK_INITRESET) { + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + } + retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, fminterval, + ((fminterval & FIT) ^ FIT) | hc_fminterval); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, periodicstart, + ((9 *hc_fminterval) / 10) & 0x3fff); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); + if (retval) + return retval; + if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { + if (!(quirk & OHCI_QUIRK_INITRESET)) { + quirk |= OHCI_QUIRK_INITRESET; + goto retry; + } else + dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", + fminterval, periodicstart); + } /* start controller operations */ + hc_control &= OHCI_CTRL_RWC; + hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; + retval = ftdi_write_pcimem(ftdi, control, hc_control); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, intrstatus, mask); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, intrdisable, + OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | + OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | + OHCI_INTR_SO); + if (retval) + return retval; /* handle root hub init quirks ... */ + retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); + if (retval) + return retval; + roothub_a &= ~(RH_A_PSM | RH_A_OCPM); + if (quirk & OHCI_QUIRK_SUPERIO) { + roothub_a |= RH_A_NOCP; + roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); + retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); + if (retval) + return retval; + } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { + roothub_a |= RH_A_NPS; + retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); + if (retval) + return retval; + } + retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); + if (retval) + return retval; + retval = ftdi_write_pcimem(ftdi, roothub.b, + (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); + if (retval) + return retval; + retval = ftdi_read_pcimem(ftdi, control, &control); + if (retval) + return retval; + mdelay((roothub_a >> 23) & 0x1fe); + for (temp = 0; temp < num_ports; temp++) { + u32 portstatus; + retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], + &portstatus); + if (retval) + return retval; + if (1 & portstatus) + devices += 1; + } + return devices; +} + +static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) { u32 latence_timer; - u32 controlreg; int UxxxStatus; u32 pcidata; int reg = 0; - int foundOHCI = 0; - u8 fn; - int activePCIfn = 0; - u32 pciVID = 0; - u32 pciPID = 0; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); + int activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); + reg = 16; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xFFFFFFFF); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, + 0xF0000000); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); + reg = 12; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &latence_timer); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + latence_timer &= 0xFFFF00FF; + latence_timer |= 0x00001600; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + latence_timer); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + reg = 4; + UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, + 0x06); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); if (UxxxStatus) return UxxxStatus; - msleep(1000); - for (fn = 0; (fn < 4) && (!foundOHCI); fn++) { - activePCIfn = fn << 8; - ftdi->function = fn + 1; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); + for (reg = 0; reg <= 0x54; reg += 4) { + UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); if (UxxxStatus) return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == 0x1045) && (pciPID == 0xc861)) { - foundOHCI = 1; - } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) { - foundOHCI = 1; - } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) { - foundOHCI = 1; - } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) { - foundOHCI = 1; - } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) { - } - } - if (foundOHCI == 0) { - return -ENXIO; } - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; + return 0; +} + +static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) +{ + u32 latence_timer; + int UxxxStatus; + u32 pcidata; + int reg = 0; + int activePCIfn = fn << 8; UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); if (UxxxStatus) return UxxxStatus; @@ -2377,7 +2590,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) if (UxxxStatus) return UxxxStatus; UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); + 0x00000000); if (UxxxStatus) return UxxxStatus; UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, @@ -2401,7 +2614,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) return UxxxStatus; reg = 4; UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); + 0x00); if (UxxxStatus) return UxxxStatus; UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, @@ -2411,159 +2624,139 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) return 0; } +static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) +{ + int result; + int UxxxStatus; + UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); + if (UxxxStatus) + return UxxxStatus; + result = ftdi_elan_check_controller(ftdi, quirk); + UxxxStatus = ftdi_elan_close_controller(ftdi, fn); + if (UxxxStatus) + return UxxxStatus; + return result; +} + +static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) +{ + u32 controlreg; + u8 sensebits; + int UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); + if (UxxxStatus) + return UxxxStatus; + msleep(750); + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); + if (UxxxStatus) + return UxxxStatus; + msleep(250); + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); + if (UxxxStatus) + return UxxxStatus; + msleep(1000); + sensebits = (controlreg >> 16) & 0x000F; + if (0x0D == sensebits) + return 0; + else + return - ENXIO; +} + static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) { + int UxxxStatus; u32 pcidata; - int U132Status; - int reg; - int reset_repeat = 0; - do_reset:reg = 8; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01); - if (U132Status) - return U132Status; - reset_check:{ - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - if (pcidata & 1) { - msleep(500); - if (reset_repeat++ > 100) { - reset_repeat = 0; - goto do_reset; - } else - goto reset_check; + int reg = 0; + u8 fn; + int activePCIfn = 0; + int max_devices = 0; + int controllers = 0; + int unrecognized = 0; + ftdi->function = 0; + for (fn = 0; (fn < 4); fn++) { + u32 pciVID = 0; + u32 pciPID = 0; + int devices = 0; + activePCIfn = fn << 8; + UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, + &pcidata); + if (UxxxStatus) + return UxxxStatus; + pciVID = pcidata & 0xFFFF; + pciPID = (pcidata >> 16) & 0xFFFF; + if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) + { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) + { + devices = ftdi_elan_found_controller(ftdi, fn, 0); + controllers += 1; + } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { + devices = ftdi_elan_found_controller(ftdi, fn, + OHCI_QUIRK_AMD756); + controllers += 1; + } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { + devices = ftdi_elan_found_controller(ftdi, fn, + OHCI_QUIRK_ZFMICRO); + controllers += 1; + } else if (0 == pcidata) { + } else + unrecognized += 1; + if (devices > max_devices) { + max_devices = devices; + ftdi->function = fn + 1; + ftdi->platform_data.vendor = pciVID; + ftdi->platform_data.device = pciPID; } } - goto dump_regs; - msleep(500); - reg = 0x28; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x40; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x34; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 4; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - msleep(250); - reg = 8; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x28; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 8; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x48; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x54; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x58; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x34; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - msleep(100); - reg = 0x50; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000); - if (U132Status) - return U132Status; - reg = 0x54; - power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - if (!(pcidata & 1)) { - msleep(500); - goto power_check; - } - msleep(3000); - reg = 0x54; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x58; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x54; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x54; - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10); - if (U132Status) - return U132Status; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - msleep(750); - reg = 0x54; - if (0) { - U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); - if (U132Status) - return U132Status; - } - if (0) { - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - } - reg = 0x54; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - reg = 0x58; - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; - dump_regs:for (reg = 0; reg <= 0x54; reg += 4) { - U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (U132Status) - return U132Status; + if (ftdi->function > 0) { + UxxxStatus = ftdi_elan_setup_controller(ftdi, + ftdi->function - 1); + if (UxxxStatus) + return UxxxStatus; + return 0; + } else if (controllers > 0) { + return -ENXIO; + } else if (unrecognized > 0) { + return -ENXIO; + } else { + ftdi->enumerated = 0; + return -ENXIO; } - return 0; } @@ -2688,6 +2881,7 @@ static void ftdi_elan_disconnect(struct usb_interface *interface) platform_device_unregister(&ftdi->platform_dev); ftdi->synchronized = 0; ftdi->enumerated = 0; + ftdi->initialized = 0; ftdi->registered = 0; } flush_workqueue(status_queue); diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index 7163f05c5b2..0d9de2f7393 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -282,6 +282,7 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id) dev->dev = NULL; goto out; } + dev_set_drvdata(dev->dev, dev); servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1; diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index bf26c3c5699..9148694627d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -403,7 +403,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (u32)SISUSB_HADDR(x, y), 2, &written); + (long)SISUSB_HADDR(x, y), 2, &written); mutex_unlock(&sisusb->lock); } @@ -438,7 +438,7 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (u32)SISUSB_HADDR(x, y), count * 2, &written); + (long)SISUSB_HADDR(x, y), count * 2, &written); mutex_unlock(&sisusb->lock); } @@ -492,7 +492,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (u32)SISUSB_HADDR(x, y), length, &written); + (long)SISUSB_HADDR(x, y), length, &written); mutex_unlock(&sisusb->lock); } @@ -564,7 +564,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (u32)SISUSB_HADDR(dx, dy), length, &written); + (long)SISUSB_HADDR(dx, dy), length, &written); mutex_unlock(&sisusb->lock); } @@ -612,7 +612,7 @@ sisusbcon_switch(struct vc_data *c) length); sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, - (u32)SISUSB_HADDR(0, 0), + (long)SISUSB_HADDR(0, 0), length, &written); mutex_unlock(&sisusb->lock); @@ -939,7 +939,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (u32)SISUSB_HADDR(0, t), length, &written); + (long)SISUSB_HADDR(0, t), length, &written); mutex_unlock(&sisusb->lock); diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 33cd91d11ec..67e2fc20eee 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -120,8 +120,8 @@ static void tv_disconnect(struct usb_interface *interface) struct trancevibrator *dev; dev = usb_get_intfdata (interface); - usb_set_intfdata(interface, NULL); device_remove_file(&interface->dev, &dev_attr_speed); + usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); kfree(dev); } diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 95e682e2c9d..896449f0cf8 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -898,7 +898,7 @@ static int ax88772_link_reset(struct usbnet *dev) static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) { - int ret; + int ret, embd_phy; void *buf; u16 rx_ctl; struct asix_data *data = (struct asix_data *)&dev->data; @@ -919,13 +919,15 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0) goto out2; + /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ + embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, - 0x0000, 0, 0, buf)) < 0) { + embd_phy, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); goto out2; } - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD)) < 0) + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0) goto out2; msleep(150); @@ -933,8 +935,14 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) goto out2; msleep(150); - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) - goto out2; + if (embd_phy) { + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0) + goto out2; + } + else { + if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0) + goto out2; + } msleep(150); rx_ctl = asix_read_rx_ctl(dev); diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index a3242be2195..a6f0f4d934d 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -79,160 +79,6 @@ struct gl_header { struct gl_packet packets; }; -#ifdef GENELINK_ACK - -// FIXME: this code is incomplete, not debugged; it doesn't -// handle interrupts correctly; it should use the generic -// status IRQ code (which didn't exist back in 2001). - -struct gl_priv { - struct urb *irq_urb; - char irq_buf [INTERRUPT_BUFSIZE]; -}; - -static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value) -{ - int retval; - - retval = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - value, - 0, // index - 0, // data buffer - 0, // size - USB_CTRL_SET_TIMEOUT); - return retval; -} - -static void gl_interrupt_complete(struct urb *urb) -{ - int status = urb->status; - - 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", - __FUNCTION__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); - } - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - err("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - -static int gl_interrupt_read(struct usbnet *dev) -{ - struct gl_priv *priv = dev->priv_data; - int retval; - - // issue usb interrupt read - if (priv && priv->irq_urb) { - // submit urb - if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0) - dbg("gl_interrupt_read: submit fail - %X...", retval); - else - dbg("gl_interrupt_read: submit success..."); - } - - return 0; -} - -// check whether another side is connected -static int genelink_check_connect(struct usbnet *dev) -{ - int retval; - - dbg("genelink_check_connect..."); - - // detect whether another side is connected - if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) { - dbg("%s: genelink_check_connect write fail - %X", - dev->net->name, retval); - return retval; - } - - // usb interrupt read to ack another side - if ((retval = gl_interrupt_read(dev)) != 0) { - dbg("%s: genelink_check_connect read fail - %X", - dev->net->name, retval); - return retval; - } - - dbg("%s: genelink_check_connect read success", dev->net->name); - return 0; -} - -// allocate and initialize the private data for genelink -static int genelink_init(struct usbnet *dev) -{ - struct gl_priv *priv; - - // allocate the private data structure - if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) { - dbg("%s: cannot allocate private data per device", - dev->net->name); - return -ENOMEM; - } - - // allocate irq urb - if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) { - dbg("%s: cannot allocate private irq urb per device", - dev->net->name); - kfree(priv); - return -ENOMEM; - } - - // fill irq urb - usb_fill_int_urb(priv->irq_urb, dev->udev, - usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE), - priv->irq_buf, INTERRUPT_BUFSIZE, - gl_interrupt_complete, 0, - GENELINK_INTERRUPT_INTERVAL); - - // set private data pointer - dev->priv_data = priv; - - return 0; -} - -// release the private data -static int genelink_free(struct usbnet *dev) -{ - struct gl_priv *priv = dev->priv_data; - - if (!priv) - return 0; - -// FIXME: can't cancel here; it's synchronous, and -// should have happened earlier in any case (interrupt -// handling needs to be generic) - - // cancel irq urb first - usb_kill_urb(priv->irq_urb); - - // free irq urb - usb_free_urb(priv->irq_urb); - - // free the private data structure - kfree(priv); - - return 0; -} - -#endif - static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { struct gl_header *header; diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index ea5f44de3de..a322a16d9cf 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -379,6 +379,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) { int retval; struct net_device *net = dev->net; + struct cdc_state *info = (void *) &dev->data; union { void *buf; struct rndis_msg_hdr *header; @@ -397,7 +398,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) - goto done; + goto fail; net->hard_header_len += sizeof (struct rndis_data_hdr); @@ -412,10 +413,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); -fail: - usb_driver_release_interface(driver_of(intf), - ((struct cdc_state *)&(dev->data))->data); - goto done; + goto fail_and_release; } dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); /* REVISIT: peripheral "alignment" request is ignored ... */ @@ -431,7 +429,7 @@ fail: retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); - goto fail; + goto fail_and_release; } tmp = le32_to_cpu(u.get_c->offset); if (unlikely((tmp + 8) > (1024 - ETH_ALEN) @@ -439,7 +437,7 @@ fail: dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", tmp, le32_to_cpu(u.get_c->len)); retval = -EDOM; - goto fail; + goto fail_and_release; } memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN); @@ -455,11 +453,18 @@ fail: retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); - goto fail; + goto fail_and_release; } retval = 0; -done: + + kfree(u.buf); + return retval; + +fail_and_release: + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver_of(intf), info->data); +fail: kfree(u.buf); return retval; } diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index c54235f73cb..670262a38a0 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -124,10 +124,11 @@ #define RX_URB_FAIL 3 /* Define these values to match your device */ -#define VENDOR_ID_REALTEK 0x0bda +#define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_MELCO 0x0411 -#define VENDOR_ID_MICRONET 0x3980 +#define VENDOR_ID_MICRONET 0x3980 #define VENDOR_ID_LONGSHINE 0x07b8 +#define VENDOR_ID_OQO 0x1557 #define VENDOR_ID_ZYXEL 0x0586 #define PRODUCT_ID_RTL8150 0x8150 @@ -144,6 +145,7 @@ static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, + {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)}, {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)}, {} }; @@ -282,7 +284,8 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg) u8 data[3], tmp; data[0] = phy; - *(data + 1) = cpu_to_le16p(®); + data[1] = reg & 0xff; + data[2] = (reg >> 8) & 0xff; tmp = indx | PHY_WRITE | PHY_GO; i = 0; diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 96c73726d74..f2ca76a9cba 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -19,8 +19,11 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1410, 0x1130) }, /* Novatel Wireless S720 CDMA/EV-DO */ + { USB_DEVICE(0x1410, 0x2110) }, /* Novatel Wireless U720 CDMA/EV-DO */ { USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ + { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 2f9b7ac3266..7ebaffd6ed8 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -69,6 +69,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 45cdf9bc43b..6bc1f404e18 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -962,21 +962,6 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi cypress_set_termios(port, &priv->tmp_termios); return (0); break; - /* these are called when setting baud rate from gpsd */ - case TCGETS: - if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { - return -EFAULT; - } - return (0); - break; - case TCSETS: - if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { - return -EFAULT; - } - /* here we need to call cypress_set_termios to invoke the new settings */ - cypress_set_termios(port, &priv->tmp_termios); - return (0); - break; /* This code comes from drivers/char/serial.c and ftdi_sio.c */ case TIOCMIWAIT: while (priv != NULL) { diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 41b0ad2d56a..6986e756f7c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -452,6 +452,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index bae117d359a..40dd394de58 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -312,8 +312,9 @@ /* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an in-circuit-debugger */ /* unit for PIC16's/PIC18's */ -#define FTDI_CCSICDU20_0_PID 0xF9D0 -#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSICDU20_0_PID 0xF9D0 +#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSMACHX_2_PID 0xF9D2 /* Inside Accesso contactless reader (http://www.insidefr.com) */ #define INSIDE_ACCESSO 0xFAD0 diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 77b977206a8..2bebd63d5ed 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -14,6 +14,9 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <asm/uaccess.h> + +static int debug; static struct usb_device_id id_table [] = { { USB_DEVICE(0x1404, 0xcddc) }, @@ -21,6 +24,26 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); +static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct ktermios t; + + dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); + + if (cmd == TCSETSF) { + if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) + return -EFAULT; + + dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, + t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); + + if (!(t.c_lflag & ICANON)) + return -EINVAL; + } + return -ENOIOCTLCMD; +} + static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -39,6 +62,7 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, + .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) @@ -63,3 +87,6 @@ static void __exit funsoft_exit(void) module_init(funsoft_init); module_exit(funsoft_exit); MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 73d755df484..5c4b06a99ac 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -87,10 +87,6 @@ static int klsi_105_write_room (struct usb_serial_port *port); static void klsi_105_read_bulk_callback (struct urb *urb); static void klsi_105_set_termios (struct usb_serial_port *port, struct ktermios *old); -static int klsi_105_ioctl (struct usb_serial_port *port, - struct file * file, - unsigned int cmd, - unsigned long arg); static void klsi_105_throttle (struct usb_serial_port *port); static void klsi_105_unthrottle (struct usb_serial_port *port); /* @@ -140,7 +136,6 @@ static struct usb_serial_driver kl5kusb105d_device = { .chars_in_buffer = klsi_105_chars_in_buffer, .write_room = klsi_105_write_room, .read_bulk_callback =klsi_105_read_bulk_callback, - .ioctl = klsi_105_ioctl, .set_termios = klsi_105_set_termios, /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, @@ -899,69 +894,6 @@ static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file, */ return retval; } - -static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct klsi_105_private *priv = usb_get_serial_port_data(port); - void __user *user_arg = (void __user *)arg; - - dbg("%scmd=0x%x", __FUNCTION__, cmd); - - /* Based on code from acm.c and others */ - switch (cmd) { - case TIOCMIWAIT: - /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ - /* TODO */ - dbg("%s - TIOCMIWAIT not handled", __FUNCTION__); - return -ENOIOCTLCMD; - case TIOCGICOUNT: - /* return count of modemline transitions */ - /* TODO */ - dbg("%s - TIOCGICOUNT not handled", __FUNCTION__); - return -ENOIOCTLCMD; - case TCGETS: - /* return current info to caller */ - dbg("%s - TCGETS data faked/incomplete", __FUNCTION__); - - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) - return -EFAULT; - - if (kernel_termios_to_user_termios((struct termios __user *)arg, - &priv->termios)) - return -EFAULT; - return 0; - case TCSETS: - /* set port termios to the one given by the user */ - dbg("%s - TCSETS not handled", __FUNCTION__); - - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) - return -EFAULT; - - if (user_termios_to_kernel_termios(&priv->termios, - (struct termios __user *)arg)) - return -EFAULT; - klsi_105_set_termios(port, &priv->termios); - return 0; - case TCSETSW: { - /* set port termios and try to wait for completion of last - * write operation */ - /* We guess here. If there are not too many write urbs - * outstanding, we lie. */ - /* what is the right way to wait here? schedule() ? */ - /* - while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE) - schedule(); - */ - return -ENOIOCTLCMD; - } - default: - dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd); - return(-ENOIOCTLCMD); - break; - } - return 0; -} /* klsi_105_ioctl */ static void klsi_105_throttle (struct usb_serial_port *port) { diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 8cc728a49e4..83f661403ba 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2460,12 +2460,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, tty_ldisc_deref(ld); return 0; - case TCGETS: - if (kernel_termios_to_user_termios - ((struct termios __user *)argp, tty->termios)) - return -EFAULT; - return 0; - case TIOCSERGETLSR: dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); return mos7840_get_lsr_info(mos7840_port, argp); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0ae4098718c..0fed43a9687 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -78,7 +78,9 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_PRODUCT_FUSION2 0x6300 #define OPTION_PRODUCT_COBRA 0x6500 #define OPTION_PRODUCT_COBRA2 0x6600 +#define OPTION_PRODUCT_GTMAX36 0x6701 #define HUAWEI_PRODUCT_E600 0x1001 +#define HUAWEI_PRODUCT_E220 0x1003 #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 #define NOVATELWIRELESS_PRODUCT_U740 0x1400 #define ANYDATA_PRODUCT_ID 0x6501 @@ -89,7 +91,9 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, @@ -102,7 +106,9 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, @@ -622,6 +628,9 @@ static int option_send_setup(struct usb_serial_port *port) dbg("%s", __FUNCTION__); + if (port->number != 0) + return 0; + portdata = usb_get_serial_port_data(port); if (port->tty) { diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index db8b26012c7..b49f2a78189 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -153,6 +153,13 @@ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by <honkkis@gmail.com> */ +UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, + "Nokia", + "E70", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), + /* Reported by Jon Hart <Jon.Hart@web.de> */ UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, "Nokia", @@ -190,6 +197,13 @@ UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Reported by Manuel Osdoba <manuel.osdoba@tu-ilmenau.de> */ +UNUSUAL_DEV( 0x0421, 0x0492, 0x0452, 0x0452, + "Nokia", + "Nokia 6233", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Alex Corcoles <alex@corcoles.net> */ UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, "Nokia", @@ -247,6 +261,18 @@ UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101, US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0), #endif +/* + * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.) + * Reported by Pete Zaitcev <zaitcev@redhat.com> + * This device chokes on both version of MODE SENSE which we have, so + * use_10_for_ms is not effective, and we use US_FL_NO_WP_DETECT. + */ +UNUSUAL_DEV( 0x046b, 0xff40, 0x0100, 0x0100, + "AMI", + "Virtual Floppy", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NO_WP_DETECT), + /* Patch submitted by Philipp Friedrich <philipp@void.at> */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, "Kyocera", @@ -721,7 +747,7 @@ UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999, "Apple", "iPod", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), + US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999, "Apple", @@ -1328,6 +1354,15 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* This prevents the kernel from detecting the virtual cd-drive with the + * Windows drivers. <johann.wilhelm@student.tugraz.at> +*/ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff, + "HUAWEI", + "E220 USB-UMTS Install", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE), + /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */ UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001, "Minolta", @@ -1342,6 +1377,21 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Francesco Foresti <frafore@tiscali.it> */ +UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, + "Super Top", + "IDE DEVICE", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + +/* Reported by Robert Schedel <r.schedel@yahoo.de> + * Note: this is a 'super top' device like the above 14cd/6600 device */ +UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, + "Teac", + "HD-35PUK-B", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* patch submitted by Davide Perini <perini.davide@dpsoftware.org> * and Renato Perini <rperini@email.it> */ diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 3feddf89d10..2e976ffcde0 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1834,7 +1834,7 @@ static void aty128_bl_init(struct aty128fb_par *par) snprintf(name, sizeof(name), "aty128bl%d", info->node); - bd = backlight_device_register(name, par, &aty128_bl_data); + bd = backlight_device_register(name, info->dev, par, &aty128_bl_data); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "aty128: Backlight registration failed\n"); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 09684d7a7ce..f2ebdd88008 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2211,7 +2211,7 @@ static void aty_bl_init(struct atyfb_par *par) snprintf(name, sizeof(name), "atybl%d", info->node); - bd = backlight_device_register(name, par, &aty_bl_data); + bd = backlight_device_register(name, info->dev, par, &aty_bl_data); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "aty: Backlight registration failed\n"); diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 585eb7b9e63..3abfd4a380c 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -163,7 +163,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node); - bd = backlight_device_register(name, pdata, &radeon_bl_data); + bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data); if (IS_ERR(bd)) { rinfo->info->bl_dev = NULL; printk("radeonfb: Backlight registration failed\n"); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index db8c191b120..9601bfe309a 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -216,8 +216,10 @@ static const struct class_device_attribute bl_class_device_attributes[] = { * Creates and registers new backlight class_device. Returns either an * ERR_PTR() or a pointer to the newly allocated device. */ -struct backlight_device *backlight_device_register(const char *name, void *devdata, - struct backlight_properties *bp) +struct backlight_device *backlight_device_register(const char *name, + struct device *dev, + void *devdata, + struct backlight_properties *bp) { int i, rc; struct backlight_device *new_bd; @@ -232,6 +234,7 @@ struct backlight_device *backlight_device_register(const char *name, void *devda new_bd->props = bp; memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev)); new_bd->class_dev.class = &backlight_class; + new_bd->class_dev.dev = dev; strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN); class_set_devdata(&new_bd->class_dev, devdata); diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 61587ca2cdb..fde1d951812 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -121,7 +121,7 @@ static int corgibl_probe(struct platform_device *pdev) machinfo->limit_mask = -1; corgi_backlight_device = backlight_device_register ("corgi-bl", - NULL, &corgibl_data); + &pdev->dev, NULL, &corgibl_data); if (IS_ERR (corgi_backlight_device)) return PTR_ERR (corgi_backlight_device); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 1c569fb543a..c07d8207fb5 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -105,7 +105,7 @@ static struct backlight_properties hp680bl_data = { static int __init hp680bl_probe(struct platform_device *dev) { hp680_backlight_device = backlight_device_register ("hp680-bl", - NULL, &hp680bl_data); + &dev->dev, NULL, &hp680bl_data); if (IS_ERR (hp680_backlight_device)) return PTR_ERR (hp680_backlight_device); diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 2d7905410b2..fc812d96c31 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -184,7 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev) local_irq_restore(flags); - locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data); + locomolcd_bl_device = backlight_device_register("locomo-bl", &ldev->dev, NULL, &locomobl_data); if (IS_ERR (locomolcd_bl_device)) return PTR_ERR (locomolcd_bl_device); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index c66e3d52cbf..9bb6257d691 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -320,7 +320,7 @@ static int __devinit bw2_init_one(struct of_device *op) all->info.fbops = &bw2_ops; all->info.screen_base = - sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); + of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); all->info.par = &all->par; bw2_blank(0, &all->info); @@ -329,8 +329,10 @@ static int __devinit bw2_init_one(struct of_device *op) err= register_framebuffer(&all->info); if (err < 0) { - of_iounmap(all->par.regs, sizeof(struct bw2_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct bw2_regs)); + of_iounmap(&op->resource[0], + all->info.screen_base, all->par.fbsize); kfree(all); return err; } @@ -351,18 +353,18 @@ static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id return bw2_init_one(op); } -static int __devexit bw2_remove(struct of_device *dev) +static int __devexit bw2_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); - of_iounmap(all->par.regs, sizeof(struct bw2_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs)); + of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index 7f926c619b6..ec6a51a5822 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -452,16 +452,20 @@ struct all_info { struct cg14_par par; }; -static void cg14_unmap_regs(struct all_info *all) +static void cg14_unmap_regs(struct of_device *op, struct all_info *all) { if (all->par.regs) - of_iounmap(all->par.regs, sizeof(struct cg14_regs)); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct cg14_regs)); if (all->par.clut) - of_iounmap(all->par.clut, sizeof(struct cg14_clut)); + of_iounmap(&op->resource[0], + all->par.clut, sizeof(struct cg14_clut)); if (all->par.cursor) - of_iounmap(all->par.cursor, sizeof(struct cg14_cursor)); + of_iounmap(&op->resource[0], + all->par.cursor, sizeof(struct cg14_cursor)); if (all->info.screen_base) - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[1], + all->info.screen_base, all->par.fbsize); } static int __devinit cg14_init_one(struct of_device *op) @@ -506,7 +510,7 @@ static int __devinit cg14_init_one(struct of_device *op) if (!all->par.regs || !all->par.clut || !all->par.cursor || !all->info.screen_base) - cg14_unmap_regs(all); + cg14_unmap_regs(op, all); is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) == (8 * 1024 * 1024)); @@ -541,7 +545,7 @@ static int __devinit cg14_init_one(struct of_device *op) __cg14_reset(&all->par); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - cg14_unmap_regs(all); + cg14_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -552,7 +556,7 @@ static int __devinit cg14_init_one(struct of_device *op) err = register_framebuffer(&all->info); if (err < 0) { fb_dealloc_cmap(&all->info.cmap); - cg14_unmap_regs(all); + cg14_unmap_regs(op, all); kfree(all); return err; } @@ -574,18 +578,18 @@ static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id return cg14_init_one(op); } -static int __devexit cg14_remove(struct of_device *dev) +static int __devexit cg14_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - cg14_unmap_regs(all); + cg14_unmap_regs(op, all); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 9c8c753ef45..ada6f7e3a89 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -403,8 +403,10 @@ static int __devinit cg3_init_one(struct of_device *op) cg3_do_default_mode(&all->par); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - of_iounmap(all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct cg3_regs)); + of_iounmap(&op->resource[0], + all->info.screen_base, all->par.fbsize); kfree(all); return -ENOMEM; } @@ -415,8 +417,10 @@ static int __devinit cg3_init_one(struct of_device *op) err = register_framebuffer(&all->info); if (err < 0) { fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct cg3_regs)); + of_iounmap(&op->resource[0], + all->info.screen_base, all->par.fbsize); kfree(all); return err; } @@ -436,19 +440,19 @@ static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id return cg3_init_one(op); } -static int __devexit cg3_remove(struct of_device *dev) +static int __devexit cg3_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs)); + of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 64146be2eeb..4dad23a28f5 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -658,21 +658,26 @@ struct all_info { struct cg6_par par; }; -static void cg6_unmap_regs(struct all_info *all) +static void cg6_unmap_regs(struct of_device *op, struct all_info *all) { if (all->par.fbc) - of_iounmap(all->par.fbc, 4096); + of_iounmap(&op->resource[0], all->par.fbc, 4096); if (all->par.tec) - of_iounmap(all->par.tec, sizeof(struct cg6_tec)); + of_iounmap(&op->resource[0], + all->par.tec, sizeof(struct cg6_tec)); if (all->par.thc) - of_iounmap(all->par.thc, sizeof(struct cg6_thc)); + of_iounmap(&op->resource[0], + all->par.thc, sizeof(struct cg6_thc)); if (all->par.bt) - of_iounmap(all->par.bt, sizeof(struct bt_regs)); + of_iounmap(&op->resource[0], + all->par.bt, sizeof(struct bt_regs)); if (all->par.fhc) - of_iounmap(all->par.fhc, sizeof(u32)); + of_iounmap(&op->resource[0], + all->par.fhc, sizeof(u32)); if (all->info.screen_base) - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->info.screen_base, all->par.fbsize); } static int __devinit cg6_init_one(struct of_device *op) @@ -720,7 +725,7 @@ static int __devinit cg6_init_one(struct of_device *op) all->par.fbsize, "cgsix ram"); if (!all->par.fbc || !all->par.tec || !all->par.thc || !all->par.bt || !all->par.fhc || !all->info.screen_base) { - cg6_unmap_regs(all); + cg6_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -734,7 +739,7 @@ static int __devinit cg6_init_one(struct of_device *op) cg6_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - cg6_unmap_regs(all); + cg6_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -744,7 +749,7 @@ static int __devinit cg6_init_one(struct of_device *op) err = register_framebuffer(&all->info); if (err < 0) { - cg6_unmap_regs(all); + cg6_unmap_regs(op, all); fb_dealloc_cmap(&all->info.cmap); kfree(all); return err; @@ -767,18 +772,18 @@ static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id return cg6_init_one(op); } -static int __devexit cg6_remove(struct of_device *dev) +static int __devexit cg6_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - cg6_unmap_regs(all); + cg6_unmap_regs(op, all); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 949141bd44d..15854aec318 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -910,7 +910,8 @@ static int ffb_init_one(struct of_device *op) all->par.dac = of_ioremap(&op->resource[1], 0, sizeof(struct ffb_dac), "ffb dac"); if (!all->par.dac) { - of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); + of_iounmap(&op->resource[2], + all->par.fbc, sizeof(struct ffb_fbc)); kfree(all); return -ENOMEM; } @@ -968,8 +969,10 @@ static int ffb_init_one(struct of_device *op) if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { printk(KERN_ERR "ffb: Could not allocate color map.\n"); - of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(all->par.dac, sizeof(struct ffb_dac)); + of_iounmap(&op->resource[2], + all->par.fbc, sizeof(struct ffb_fbc)); + of_iounmap(&op->resource[1], + all->par.dac, sizeof(struct ffb_dac)); kfree(all); return -ENOMEM; } @@ -980,8 +983,10 @@ static int ffb_init_one(struct of_device *op) if (err < 0) { printk(KERN_ERR "ffb: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(all->par.dac, sizeof(struct ffb_dac)); + of_iounmap(&op->resource[2], + all->par.fbc, sizeof(struct ffb_fbc)); + of_iounmap(&op->resource[1], + all->par.dac, sizeof(struct ffb_dac)); kfree(all); return err; } @@ -1003,19 +1008,19 @@ static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id return ffb_init_one(op); } -static int __devexit ffb_remove(struct of_device *dev) +static int __devexit ffb_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(all->par.dac, sizeof(struct ffb_dac)); + of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc)); + of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac)); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index 3adf6ab0768..23a6bcc3e3c 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -1,5 +1,5 @@ /* - * Frame buffer device for IBM GXT4500P display adaptor + * Frame buffer device for IBM GXT4500P and GXT6000P display adaptors * * Copyright (C) 2006 Paul Mackerras, IBM Corp. <paulus@samba.org> */ @@ -11,8 +11,10 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/delay.h> +#include <linux/string.h> #define PCI_DEVICE_ID_IBM_GXT4500P 0x21c +#define PCI_DEVICE_ID_IBM_GXT6000P 0x170 /* GXT4500P registers */ @@ -94,6 +96,7 @@ static const unsigned char pixsize[] = { #define PLL_M 0x4040 #define PLL_N 0x4044 #define PLL_POSTDIV 0x4048 +#define PLL_C 0x404c /* Hardware cursor */ #define CURSOR_X 0x4078 @@ -140,6 +143,7 @@ struct gxt4500_par { int pixfmt; /* pixel format, see DFA_PIX_* values */ /* PLL parameters */ + int refclk_ps; /* ref clock period in picoseconds */ int pll_m; /* ref clock divisor */ int pll_n; /* VCO divisor */ int pll_pd1; /* first post-divisor */ @@ -166,6 +170,21 @@ static const struct fb_videomode defaultmode __devinitdata = { .vmode = FB_VMODE_NONINTERLACED }; +/* List of supported cards */ +enum gxt_cards { + GXT4500P, + GXT6000P +}; + +/* Card-specific information */ +static const struct cardinfo { + int refclk_ps; /* period of PLL reference clock in ps */ + const char *cardname; +} cardinfo[] = { + [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" }, + [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" }, +}; + /* * The refclk and VCO dividers appear to use a linear feedback shift * register, which gets reloaded when it reaches a terminal value, at @@ -203,27 +222,16 @@ static const unsigned char ndivtab[] = { /* 130 */ 0x9e, 0x4f, 0x27, 0x93, 0xc9, 0xe4, 0x72, 0x39, 0x1c, 0x0e, /* 140 */ 0x87, 0xc3, 0x61, 0x30, 0x18, 0x8c, 0xc6, 0x63, 0x31, 0x98, /* 150 */ 0xcc, 0xe6, 0x73, 0xb9, 0x5c, 0x2e, 0x97, 0x4b, 0xa5, 0xd2, -/* 160 */ 0x69, 0xb4, 0xda, 0xed, 0x76, 0xbb, 0x5d, 0xae, 0xd7, 0x6b, -/* 170 */ 0xb5, 0x5a, 0xad, 0x56, 0xab, 0xd5, 0x6a, 0x35, 0x1a, 0x8d, -/* 180 */ 0x46, 0x23, 0x11, 0x88, 0x44, 0x22, 0x91, 0xc8, 0x64, 0x32, -/* 190 */ 0x19, 0x0c, 0x86, 0x43, 0x21, 0x10, 0x08, 0x04, 0x02, 0x81, -/* 200 */ 0x40, 0xa0, 0xd0, 0x68, 0x34, 0x9a, 0xcd, 0x66, 0x33, 0x99, -/* 210 */ 0x4c, 0xa6, 0x53, 0xa9, 0xd4, 0xea, 0x75, 0x3a, 0x9d, 0xce, -/* 220 */ 0xe7, 0xf3, 0xf9, 0x7c, 0x3e, 0x1f, 0x8f, 0x47, 0xa3, 0x51, -/* 230 */ 0xa8, 0x54, 0xaa, 0x55, 0x2a, 0x15, 0x0a, 0x05, 0x82, 0xc1, -/* 240 */ 0x60, 0xb0, 0x58, 0xac, 0xd6, 0xeb, 0xf5, 0x7a, 0xbd, 0xde, -/* 250 */ 0x6f, 0x37, 0x1b, 0x0d, 0x06, 0x03, 0x01, +/* 160 */ 0x69, }; -#define REF_PERIOD_PS 9259 /* period of reference clock in ps */ - static int calc_pll(int period_ps, struct gxt4500_par *par) { int m, n, pdiv1, pdiv2, postdiv; - int pll_period, best_error, t; + int pll_period, best_error, t, intf; - /* only deal with range 1MHz - 400MHz */ - if (period_ps < 2500 || period_ps > 1000000) + /* only deal with range 5MHz - 300MHz */ + if (period_ps < 3333 || period_ps > 200000) return -1; best_error = 1000000; @@ -231,14 +239,17 @@ static int calc_pll(int period_ps, struct gxt4500_par *par) for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) { postdiv = pdiv1 * pdiv2; pll_period = (period_ps + postdiv - 1) / postdiv; - /* keep pll in range 500..1250 MHz */ - if (pll_period < 800 || pll_period > 2000) + /* keep pll in range 350..600 MHz */ + if (pll_period < 1666 || pll_period > 2857) continue; - for (m = 3; m <= 40; ++m) { - n = REF_PERIOD_PS * m * postdiv / period_ps; - if (n < 5 || n > 256) + for (m = 1; m <= 64; ++m) { + intf = m * par->refclk_ps; + if (intf > 500000) + break; + n = intf * postdiv / period_ps; + if (n < 3 || n > 160) continue; - t = REF_PERIOD_PS * m * postdiv / n; + t = par->refclk_ps * m * postdiv / n; t -= period_ps; if (t >= 0 && t < best_error) { par->pll_m = m; @@ -257,7 +268,7 @@ static int calc_pll(int period_ps, struct gxt4500_par *par) static int calc_pixclock(struct gxt4500_par *par) { - return REF_PERIOD_PS * par->pll_m * par->pll_pd1 * par->pll_pd2 + return par->refclk_ps * par->pll_m * par->pll_pd1 * par->pll_pd2 / par->pll_n; } @@ -357,7 +368,7 @@ static int gxt4500_set_par(struct fb_info *info) struct gxt4500_par *par = info->par; struct fb_var_screeninfo *var = &info->var; int err; - u32 ctrlreg; + u32 ctrlreg, tmp; unsigned int dfa_ctl, pixfmt, stride; unsigned int wid_tiles, i; unsigned int prefetch_pix, htot; @@ -376,10 +387,25 @@ static int gxt4500_set_par(struct fb_info *info) writereg(par, DTG_CONTROL, ctrlreg); /* set PLL registers */ + tmp = readreg(par, PLL_C) & ~0x7f; + if (par->pll_n < 38) + tmp |= 0x29; + if (par->pll_n < 69) + tmp |= 0x35; + else if (par->pll_n < 100) + tmp |= 0x76; + else + tmp |= 0x7e; + writereg(par, PLL_C, tmp); writereg(par, PLL_M, mdivtab[par->pll_m - 1]); writereg(par, PLL_N, ndivtab[par->pll_n - 2]); - writereg(par, PLL_POSTDIV, - ((8 - par->pll_pd1) << 3) | (8 - par->pll_pd2)); + tmp = ((8 - par->pll_pd2) << 3) | (8 - par->pll_pd1); + if (par->pll_pd1 == 8 || par->pll_pd2 == 8) { + /* work around erratum */ + writereg(par, PLL_POSTDIV, tmp | 0x9); + udelay(1); + } + writereg(par, PLL_POSTDIV, tmp); msleep(20); /* turn off hardware cursor */ @@ -483,8 +509,8 @@ static int gxt4500_setcolreg(unsigned int reg, unsigned int red, if (reg > 1023) return 1; - cmap_entry = ((transp & 0xff00) << 16) | ((blue & 0xff00) << 8) | - (green & 0xff00) | (red >> 8); + cmap_entry = ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) | + (green & 0xff00) | (blue >> 8); writereg(par, CMAP + reg * 4, cmap_entry); if (reg < 16 && par->pixfmt != DFA_PIX_8BIT) { @@ -585,6 +611,7 @@ static int __devinit gxt4500_probe(struct pci_dev *pdev, struct gxt4500_par *par; struct fb_info *info; struct fb_var_screeninfo var; + enum gxt_cards cardtype; err = pci_enable_device(pdev); if (err) { @@ -613,7 +640,11 @@ static int __devinit gxt4500_probe(struct pci_dev *pdev, goto err_free_fb; } par = info->par; + cardtype = ent->driver_data; + par->refclk_ps = cardinfo[cardtype].refclk_ps; info->fix = gxt4500_fix; + strlcpy(info->fix.id, cardinfo[cardtype].cardname, + sizeof(info->fix.id)); info->pseudo_palette = par->pseudo_palette; info->fix.mmio_start = reg_phys; @@ -703,8 +734,10 @@ static void __devexit gxt4500_remove(struct pci_dev *pdev) /* supported chipsets */ static const struct pci_device_id gxt4500_pci_tbl[] = { - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P), + .driver_data = GXT4500P }, + { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P), + .driver_data = GXT6000P }, { 0 } }; @@ -735,7 +768,7 @@ static void __exit gxt4500_exit(void) module_exit(gxt4500_exit); MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); -MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P"); +MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6000P"); MODULE_LICENSE("GPL"); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); diff --git a/drivers/video/leo.c b/drivers/video/leo.c index f3a24338d9a..a038aa5a9e1 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -530,20 +530,21 @@ struct all_info { struct leo_par par; }; -static void leo_unmap_regs(struct all_info *all) +static void leo_unmap_regs(struct of_device *op, struct all_info *all) { if (all->par.lc_ss0_usr) - of_iounmap(all->par.lc_ss0_usr, 0x1000); + of_iounmap(&op->resource[0], all->par.lc_ss0_usr, 0x1000); if (all->par.ld_ss0) - of_iounmap(all->par.ld_ss0, 0x1000); + of_iounmap(&op->resource[0], all->par.ld_ss0, 0x1000); if (all->par.ld_ss1) - of_iounmap(all->par.ld_ss1, 0x1000); + of_iounmap(&op->resource[0], all->par.ld_ss1, 0x1000); if (all->par.lx_krn) - of_iounmap(all->par.lx_krn, 0x1000); + of_iounmap(&op->resource[0], all->par.lx_krn, 0x1000); if (all->par.cursor) - of_iounmap(all->par.cursor, sizeof(struct leo_cursor)); + of_iounmap(&op->resource[0], + all->par.cursor, sizeof(struct leo_cursor)); if (all->info.screen_base) - of_iounmap(all->info.screen_base, 0x800000); + of_iounmap(&op->resource[0], all->info.screen_base, 0x800000); } static int __devinit leo_init_one(struct of_device *op) @@ -592,7 +593,7 @@ static int __devinit leo_init_one(struct of_device *op) !all->par.lx_krn || !all->par.cursor || !all->info.screen_base) { - leo_unmap_regs(all); + leo_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -607,7 +608,7 @@ static int __devinit leo_init_one(struct of_device *op) leo_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - leo_unmap_regs(all); + leo_unmap_regs(op, all); kfree(all); return -ENOMEM;; } @@ -617,7 +618,7 @@ static int __devinit leo_init_one(struct of_device *op) err = register_framebuffer(&all->info); if (err < 0) { fb_dealloc_cmap(&all->info.cmap); - leo_unmap_regs(all); + leo_unmap_regs(op, all); kfree(all); return err; } @@ -638,18 +639,18 @@ static int __devinit leo_probe(struct of_device *dev, const struct of_device_id return leo_init_one(op); } -static int __devexit leo_remove(struct of_device *dev) +static int __devexit leo_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - leo_unmap_regs(all); + leo_unmap_regs(op, all); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 5b75ae4e945..df934bd2189 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -141,7 +141,7 @@ void nvidia_bl_init(struct nvidia_par *par) snprintf(name, sizeof(name), "nvidiabl%d", info->node); - bd = backlight_device_register(name, par, &nvidia_bl_data); + bd = backlight_device_register(name, info->dev, par, &nvidia_bl_data); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "nvidia: Backlight registration failed\n"); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 56ac51d6a7f..637b78bb4bf 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -297,7 +297,8 @@ static int __devinit p9100_init_one(struct of_device *op) all->info.screen_base = of_ioremap(&op->resource[2], 0, all->par.fbsize, "p9100 ram"); if (!all->info.screen_base) { - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct p9100_regs)); kfree(all); return -ENOMEM; } @@ -306,8 +307,10 @@ static int __devinit p9100_init_one(struct of_device *op) p9100_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(&op->resource[2], + all->info.screen_base, all->par.fbsize); kfree(all); return -ENOMEM; } @@ -317,8 +320,10 @@ static int __devinit p9100_init_one(struct of_device *op) err = register_framebuffer(&all->info); if (err < 0) { fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(&op->resource[2], + all->info.screen_base, all->par.fbsize); kfree(all); return err; } @@ -340,19 +345,19 @@ static int __devinit p9100_probe(struct of_device *dev, const struct of_device_i return p9100_init_one(op); } -static int __devexit p9100_remove(struct of_device *dev) +static int __devexit p9100_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(&op->resource[2], all->info.screen_base, all->par.fbsize); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 38eb0b69c2d..b4947c81070 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1216,7 +1216,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options) done: if (res_specified) { dev_info(dev, "overriding resolution: %dx%d\n", xres, yres); - inf->xres = xres; inf->yres = yres; + inf->modes[0].xres = xres; inf->modes[0].yres = yres; } if (bpp_specified) switch (bpp) { @@ -1225,48 +1225,48 @@ static int __init pxafb_parse_options(struct device *dev, char *options) case 4: case 8: case 16: - inf->bpp = bpp; + 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->pixclock = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override pixclock: %ld\n", inf->pixclock); + 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->left_margin = simple_strtoul(this_opt+5, NULL, 0); - dev_info(dev, "override left: %u\n", inf->left_margin); + 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->right_margin = simple_strtoul(this_opt+6, NULL, 0); - dev_info(dev, "override right: %u\n", inf->right_margin); + 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->upper_margin = simple_strtoul(this_opt+6, NULL, 0); - dev_info(dev, "override upper: %u\n", inf->upper_margin); + 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->lower_margin = simple_strtoul(this_opt+6, NULL, 0); - dev_info(dev, "override lower: %u\n", inf->lower_margin); + 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->hsync_len = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override hsynclen: %u\n", inf->hsync_len); + 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->vsync_len = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override vsynclen: %u\n", inf->vsync_len); + 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->sync &= ~FB_SYNC_HOR_HIGH_ACT; + inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT; } else { dev_info(dev, "override hsync: Active High\n"); - inf->sync |= FB_SYNC_HOR_HIGH_ACT; + 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->sync &= ~FB_SYNC_VERT_HIGH_ACT; + inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT; } else { dev_info(dev, "override vsync: Active High\n"); - inf->sync |= FB_SYNC_VERT_HIGH_ACT; + 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) { diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 345e8b1c1af..1a13966b7d5 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -384,7 +384,7 @@ static void riva_bl_init(struct riva_par *par) snprintf(name, sizeof(name), "rivabl%d", info->node); - bd = backlight_device_register(name, par, &riva_bl_data); + bd = backlight_device_register(name, info->dev, par, &riva_bl_data); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "riva: Backlight registration failed\n"); diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index cd10b18150b..5d2a4a4b731 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -1200,9 +1200,9 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state) * Our LCD controller task (which is called when we blank or unblank) * via keventd. */ -static void sa1100fb_task(void *dummy) +static void sa1100fb_task(struct work_struct *w) { - struct sa1100fb_info *fbi = dummy; + struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task); u_int state = xchg(&fbi->task_state, -1); set_ctrlr_state(fbi, state); @@ -1444,7 +1444,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) fbi->max_bpp / 8; init_waitqueue_head(&fbi->ctrlr_wait); - INIT_WORK(&fbi->task, sa1100fb_task, fbi); + INIT_WORK(&fbi->task, sa1100fb_task); init_MUTEX(&fbi->ctrlr_sem); return fbi; diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 6990ab11cd0..5a99669232c 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -350,18 +350,23 @@ struct all_info { struct tcx_par par; }; -static void tcx_unmap_regs(struct all_info *all) +static void tcx_unmap_regs(struct of_device *op, struct all_info *all) { if (all->par.tec) - of_iounmap(all->par.tec, sizeof(struct tcx_tec)); + of_iounmap(&op->resource[7], + all->par.tec, sizeof(struct tcx_tec)); if (all->par.thc) - of_iounmap(all->par.thc, sizeof(struct tcx_thc)); + of_iounmap(&op->resource[9], + all->par.thc, sizeof(struct tcx_thc)); if (all->par.bt) - of_iounmap(all->par.bt, sizeof(struct bt_regs)); + of_iounmap(&op->resource[8], + all->par.bt, sizeof(struct bt_regs)); if (all->par.cplane) - of_iounmap(all->par.cplane, all->par.fbsize * sizeof(u32)); + of_iounmap(&op->resource[4], + all->par.cplane, all->par.fbsize * sizeof(u32)); if (all->info.screen_base) - of_iounmap(all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], + all->info.screen_base, all->par.fbsize); } static int __devinit tcx_init_one(struct of_device *op) @@ -398,7 +403,7 @@ static int __devinit tcx_init_one(struct of_device *op) all->par.fbsize, "tcx ram"); if (!all->par.tec || !all->par.thc || !all->par.bt || !all->info.screen_base) { - tcx_unmap_regs(all); + tcx_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -409,7 +414,7 @@ static int __devinit tcx_init_one(struct of_device *op) all->par.fbsize * sizeof(u32), "tcx cplane"); if (!all->par.cplane) { - tcx_unmap_regs(all); + tcx_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -461,7 +466,7 @@ static int __devinit tcx_init_one(struct of_device *op) tcx_blank(FB_BLANK_UNBLANK, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - tcx_unmap_regs(all); + tcx_unmap_regs(op, all); kfree(all); return -ENOMEM; } @@ -472,7 +477,7 @@ static int __devinit tcx_init_one(struct of_device *op) err = register_framebuffer(&all->info); if (err < 0) { fb_dealloc_cmap(&all->info.cmap); - tcx_unmap_regs(all); + tcx_unmap_regs(op, all); kfree(all); return err; } @@ -495,18 +500,18 @@ static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id return tcx_init_one(op); } -static int __devexit tcx_remove(struct of_device *dev) +static int __devexit tcx_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct all_info *all = dev_get_drvdata(&op->dev); unregister_framebuffer(&all->info); fb_dealloc_cmap(&all->info.cmap); - tcx_unmap_regs(all); + tcx_unmap_regs(op, all); kfree(all); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } |